Project import
diff --git a/libchrome/Android.mk b/libchrome/Android.mk
new file mode 100644
index 0000000..e769fef
--- /dev/null
+++ b/libchrome/Android.mk
@@ -0,0 +1,635 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Default values for the USE flags. Override these USE flags from your product
+# by setting BRILLO_USE_* values. Note that we define local variables like
+# local_use_* to prevent leaking our default setting for other packages.
+local_use_dbus := $(if $(BRILLO_USE_DBUS),$(BRILLO_USE_DBUS),1)
+
+LOCAL_PATH := $(call my-dir)
+
+# Common variables
+# ========================================================
+
+# Set libchromeUseClang to "true" to force clang or "false" to force gcc.
+libchromeUseClang :=
+libchromeCommonCppExtension := .cc
+libchromeTestCFlags := -Wno-unused-parameter -Wno-unused-function \
+	-Wno-missing-field-initializers
+libchromeCommonCFlags := -Wall -Werror
+libchromeCommonCIncludes := \
+	external/valgrind/include \
+	external/valgrind \
+
+libchromeExportedCIncludes := $(LOCAL_PATH)
+
+libchromeCommonSrc := \
+	base/at_exit.cc \
+	base/base64.cc \
+	base/base64url.cc \
+	base/base_switches.cc \
+	base/bind_helpers.cc \
+	base/build_time.cc \
+	base/callback_helpers.cc \
+	base/callback_internal.cc \
+	base/command_line.cc \
+	base/cpu.cc \
+	base/debug/alias.cc \
+	base/debug/debugger.cc \
+	base/debug/debugger_posix.cc \
+	base/debug/stack_trace.cc \
+	base/debug/stack_trace_posix.cc \
+	base/debug/task_annotator.cc \
+	base/environment.cc \
+	base/files/file.cc \
+	base/files/file_enumerator.cc \
+	base/files/file_enumerator_posix.cc \
+	base/files/file_path.cc \
+	base/files/file_path_constants.cc \
+	base/files/file_path_watcher.cc \
+	base/files/file_posix.cc \
+	base/files/file_tracing.cc \
+	base/files/file_util.cc \
+	base/files/file_util_posix.cc \
+	base/files/important_file_writer.cc \
+	base/files/memory_mapped_file.cc \
+	base/files/memory_mapped_file_posix.cc \
+	base/files/scoped_file.cc \
+	base/files/scoped_temp_dir.cc \
+	base/guid.cc \
+	base/hash.cc \
+	base/json/json_file_value_serializer.cc \
+	base/json/json_parser.cc \
+	base/json/json_reader.cc \
+	base/json/json_string_value_serializer.cc \
+	base/json/json_value_converter.cc \
+	base/json/json_writer.cc \
+	base/json/string_escape.cc \
+	base/lazy_instance.cc \
+	base/location.cc \
+	base/logging.cc \
+	base/md5.cc \
+	base/memory/aligned_memory.cc \
+	base/memory/ref_counted.cc \
+	base/memory/ref_counted_memory.cc \
+	base/memory/singleton.cc \
+	base/memory/weak_ptr.cc \
+	base/message_loop/incoming_task_queue.cc \
+	base/message_loop/message_loop.cc \
+	base/message_loop/message_loop_task_runner.cc \
+	base/message_loop/message_pump.cc \
+	base/message_loop/message_pump_default.cc \
+	base/message_loop/message_pump_libevent.cc \
+	base/metrics/bucket_ranges.cc \
+	base/metrics/field_trial.cc \
+	base/metrics/metrics_hashes.cc \
+	base/metrics/histogram_base.cc \
+	base/metrics/histogram.cc \
+	base/metrics/histogram_samples.cc \
+	base/metrics/histogram_snapshot_manager.cc \
+	base/metrics/persistent_histogram_allocator.cc \
+	base/metrics/persistent_memory_allocator.cc \
+	base/metrics/persistent_sample_map.cc \
+	base/metrics/sample_map.cc \
+	base/metrics/sample_vector.cc \
+	base/metrics/sparse_histogram.cc \
+	base/metrics/statistics_recorder.cc \
+	base/pending_task.cc \
+	base/pickle.cc \
+	base/posix/file_descriptor_shuffle.cc \
+	base/posix/safe_strerror.cc \
+	base/process/kill.cc \
+	base/process/kill_posix.cc \
+	base/process/launch.cc \
+	base/process/launch_posix.cc \
+	base/process/process_handle.cc \
+	base/process/process_handle_posix.cc \
+	base/process/process_iterator.cc \
+	base/process/process_metrics.cc \
+	base/process/process_metrics_posix.cc \
+	base/process/process_posix.cc \
+	base/profiler/scoped_profile.cc \
+	base/profiler/scoped_tracker.cc \
+	base/profiler/tracked_time.cc \
+	base/rand_util.cc \
+	base/rand_util_posix.cc \
+	base/run_loop.cc \
+	base/sequence_checker_impl.cc \
+	base/sequenced_task_runner.cc \
+	base/sha1_portable.cc \
+	base/strings/pattern.cc \
+	base/strings/safe_sprintf.cc \
+	base/strings/string16.cc \
+	base/strings/string_number_conversions.cc \
+	base/strings/string_piece.cc \
+	base/strings/stringprintf.cc \
+	base/strings/string_split.cc \
+	base/strings/string_util.cc \
+	base/strings/string_util_constants.cc \
+	base/strings/utf_string_conversions.cc \
+	base/strings/utf_string_conversion_utils.cc \
+	base/synchronization/cancellation_flag.cc \
+	base/synchronization/condition_variable_posix.cc \
+	base/synchronization/lock.cc \
+	base/synchronization/lock_impl_posix.cc \
+	base/synchronization/read_write_lock_posix.cc \
+	base/synchronization/waitable_event_posix.cc \
+	base/sync_socket_posix.cc \
+	base/sys_info.cc \
+	base/sys_info_posix.cc \
+	base/task/cancelable_task_tracker.cc \
+	base/task_runner.cc \
+	base/task_scheduler/scheduler_lock_impl.cc \
+	base/task_scheduler/sequence.cc \
+	base/task_scheduler/sequence_sort_key.cc \
+	base/task_scheduler/task.cc \
+	base/task_scheduler/task_traits.cc \
+	base/third_party/icu/icu_utf.cc \
+	base/third_party/nspr/prtime.cc \
+	base/threading/non_thread_safe_impl.cc \
+	base/threading/platform_thread_posix.cc \
+	base/threading/post_task_and_reply_impl.cc \
+	base/threading/sequenced_task_runner_handle.cc \
+	base/threading/sequenced_worker_pool.cc \
+	base/threading/simple_thread.cc \
+	base/threading/thread.cc \
+	base/threading/thread_checker_impl.cc \
+	base/threading/thread_collision_warner.cc \
+	base/threading/thread_id_name_manager.cc \
+	base/threading/thread_local_posix.cc \
+	base/threading/thread_local_storage.cc \
+	base/threading/thread_local_storage_posix.cc \
+	base/threading/thread_restrictions.cc \
+	base/threading/thread_task_runner_handle.cc \
+	base/threading/worker_pool.cc \
+	base/threading/worker_pool_posix.cc \
+	base/time/clock.cc \
+	base/time/default_clock.cc \
+	base/time/default_tick_clock.cc \
+	base/time/tick_clock.cc \
+	base/time/time.cc \
+	base/time/time_posix.cc \
+	base/timer/elapsed_timer.cc \
+	base/timer/timer.cc \
+	base/trace_event/heap_profiler_allocation_context.cc \
+	base/trace_event/heap_profiler_allocation_context_tracker.cc \
+	base/trace_event/heap_profiler_allocation_register.cc \
+	base/trace_event/heap_profiler_allocation_register_posix.cc \
+	base/trace_event/heap_profiler_heap_dump_writer.cc \
+	base/trace_event/heap_profiler_stack_frame_deduplicator.cc \
+	base/trace_event/heap_profiler_type_name_deduplicator.cc \
+	base/trace_event/malloc_dump_provider.cc \
+	base/trace_event/memory_allocator_dump.cc \
+	base/trace_event/memory_allocator_dump_guid.cc \
+	base/trace_event/memory_dump_manager.cc \
+	base/trace_event/memory_dump_request_args.cc \
+	base/trace_event/memory_dump_session_state.cc \
+	base/trace_event/memory_infra_background_whitelist.cc \
+	base/trace_event/process_memory_dump.cc \
+	base/trace_event/process_memory_maps.cc \
+	base/trace_event/process_memory_totals.cc \
+	base/trace_event/trace_buffer.cc \
+	base/trace_event/trace_config.cc \
+	base/trace_event/trace_event_argument.cc \
+	base/trace_event/trace_event_impl.cc \
+	base/trace_event/trace_event_memory_overhead.cc \
+	base/trace_event/trace_event_synthetic_delay.cc \
+	base/trace_event/trace_log.cc \
+	base/trace_event/trace_log_constants.cc \
+	base/trace_event/trace_sampling_thread.cc \
+	base/tracked_objects.cc \
+	base/tracking_info.cc \
+	base/values.cc \
+	base/version.cc \
+	base/vlog.cc \
+
+libchromeLinuxSrc := \
+	base/allocator/allocator_shim.cc \
+	base/files/file_path_watcher_linux.cc \
+	base/files/file_util_linux.cc \
+	base/memory/shared_memory_posix.cc \
+	base/posix/unix_domain_socket_linux.cc \
+	base/process/internal_linux.cc \
+	base/process/process_handle_linux.cc \
+	base/process/process_iterator_linux.cc \
+	base/process/process_metrics_linux.cc \
+	base/strings/sys_string_conversions_posix.cc \
+	base/sys_info_linux.cc \
+	base/threading/platform_thread_internal_posix.cc \
+	base/threading/platform_thread_linux.cc \
+	components/timers/alarm_timer_chromeos.cc \
+
+libchromeMacSrc := \
+	base/files/file_path_watcher_fsevents.cc \
+	base/files/file_path_watcher_kqueue.cc \
+	base/files/file_path_watcher_mac.cc \
+	base/files/file_util_mac.mm \
+	base/mac/bundle_locations.mm \
+	base/mac/foundation_util.mm \
+	base/mac/mach_logging.cc \
+	base/mac/scoped_mach_port.cc \
+	base/mac/scoped_mach_vm.cc \
+	base/mac/scoped_nsautorelease_pool.mm \
+	base/mac/sdk_forward_declarations.mm \
+	base/memory/shared_memory_mac.cc \
+	base/memory/shared_memory_handle_mac.cc \
+	base/message_loop/message_pump_mac.mm \
+	base/process/launch_mac.cc \
+	base/process/port_provider_mac.cc \
+	base/process/process_handle_mac.cc \
+	base/process/process_iterator_mac.cc \
+	base/process/process_metrics_mac.cc \
+	base/strings/sys_string_conversions_mac.mm \
+	base/sys_info_mac.mm \
+	base/time/time_mac.cc \
+	base/threading/platform_thread_mac.mm \
+
+libchromeCommonUnittestSrc := \
+	base/at_exit_unittest.cc \
+	base/atomicops_unittest.cc \
+	base/base64_unittest.cc \
+	base/base64url_unittest.cc \
+	base/bind_unittest.cc \
+	base/bits_unittest.cc \
+	base/build_time_unittest.cc \
+	base/callback_helpers_unittest.cc \
+	base/callback_list_unittest.cc \
+	base/callback_unittest.cc \
+	base/cancelable_callback_unittest.cc \
+	base/command_line_unittest.cc \
+	base/cpu_unittest.cc \
+	base/debug/debugger_unittest.cc \
+	base/debug/leak_tracker_unittest.cc \
+	base/debug/task_annotator_unittest.cc \
+	base/environment_unittest.cc \
+	base/file_version_info_unittest.cc \
+	base/files/dir_reader_posix_unittest.cc \
+	base/files/file_path_watcher_unittest.cc \
+	base/files/file_path_unittest.cc \
+	base/files/file_unittest.cc \
+	base/files/important_file_writer_unittest.cc \
+	base/files/scoped_temp_dir_unittest.cc \
+	base/gmock_unittest.cc \
+	base/guid_unittest.cc \
+	base/id_map_unittest.cc \
+	base/json/json_parser_unittest.cc \
+	base/json/json_reader_unittest.cc \
+	base/json/json_value_converter_unittest.cc \
+	base/json/json_value_serializer_unittest.cc \
+	base/json/json_writer_unittest.cc \
+	base/json/string_escape_unittest.cc \
+	base/lazy_instance_unittest.cc \
+	base/logging_unittest.cc \
+	base/md5_unittest.cc \
+	base/memory/aligned_memory_unittest.cc \
+	base/memory/linked_ptr_unittest.cc \
+	base/memory/ref_counted_memory_unittest.cc \
+	base/memory/ref_counted_unittest.cc \
+	base/memory/scoped_vector_unittest.cc \
+	base/memory/singleton_unittest.cc \
+	base/memory/weak_ptr_unittest.cc \
+	base/message_loop/message_loop_test.cc \
+	base/message_loop/message_loop_task_runner_unittest.cc \
+	base/message_loop/message_loop_unittest.cc \
+	base/metrics/bucket_ranges_unittest.cc \
+	base/metrics/field_trial_unittest.cc \
+	base/metrics/metrics_hashes_unittest.cc \
+	base/metrics/histogram_base_unittest.cc \
+	base/metrics/histogram_macros_unittest.cc \
+	base/metrics/histogram_snapshot_manager_unittest.cc \
+	base/metrics/histogram_unittest.cc \
+	base/metrics/persistent_histogram_allocator_unittest.cc \
+	base/metrics/persistent_memory_allocator_unittest.cc \
+	base/metrics/persistent_sample_map_unittest.cc \
+	base/metrics/sample_map_unittest.cc \
+	base/metrics/sample_vector_unittest.cc \
+	base/metrics/sparse_histogram_unittest.cc \
+	base/metrics/statistics_recorder_unittest.cc \
+	base/numerics/safe_numerics_unittest.cc \
+	base/observer_list_unittest.cc \
+	base/optional_unittest.cc \
+	base/pickle_unittest.cc \
+	base/posix/file_descriptor_shuffle_unittest.cc \
+	base/posix/unix_domain_socket_linux_unittest.cc \
+	base/process/process_metrics_unittest.cc \
+	base/profiler/tracked_time_unittest.cc \
+	base/rand_util_unittest.cc \
+	base/scoped_clear_errno_unittest.cc \
+	base/scoped_generic_unittest.cc \
+	base/security_unittest.cc \
+	base/sequence_checker_unittest.cc \
+	base/sha1_unittest.cc \
+	base/stl_util_unittest.cc \
+	base/strings/pattern_unittest.cc \
+	base/strings/string16_unittest.cc \
+	base/strings/string_number_conversions_unittest.cc \
+	base/strings/string_piece_unittest.cc \
+	base/strings/stringprintf_unittest.cc \
+	base/strings/string_split_unittest.cc \
+	base/strings/string_util_unittest.cc \
+	base/strings/sys_string_conversions_unittest.cc \
+	base/strings/utf_string_conversions_unittest.cc \
+	base/synchronization/cancellation_flag_unittest.cc \
+	base/synchronization/condition_variable_unittest.cc \
+	base/synchronization/lock_unittest.cc \
+	base/synchronization/waitable_event_unittest.cc \
+	base/sync_socket_unittest.cc \
+	base/sys_info_unittest.cc \
+	base/task/cancelable_task_tracker_unittest.cc \
+	base/task_runner_util_unittest.cc \
+	base/task_scheduler/scheduler_lock_unittest.cc \
+	base/task_scheduler/sequence_sort_key_unittest.cc \
+	base/task_scheduler/sequence_unittest.cc \
+	base/task_scheduler/task_traits.cc \
+	base/template_util_unittest.cc \
+	base/test/multiprocess_test.cc \
+	base/test/multiprocess_test_android.cc \
+	base/test/opaque_ref_counted.cc \
+	base/test/scoped_locale.cc \
+	base/test/sequenced_worker_pool_owner.cc \
+	base/test/test_file_util.cc \
+	base/test/test_file_util_linux.cc \
+	base/test/test_file_util_posix.cc \
+	base/test/test_io_thread.cc \
+	base/test/test_pending_task.cc \
+	base/test/test_simple_task_runner.cc \
+	base/test/test_switches.cc \
+	base/test/test_timeouts.cc \
+	base/test/trace_event_analyzer.cc \
+	base/threading/non_thread_safe_unittest.cc \
+	base/threading/platform_thread_unittest.cc \
+	base/threading/simple_thread_unittest.cc \
+	base/threading/thread_checker_unittest.cc \
+	base/threading/thread_collision_warner_unittest.cc \
+	base/threading/thread_id_name_manager_unittest.cc \
+	base/threading/thread_local_storage_unittest.cc \
+	base/threading/thread_local_unittest.cc \
+	base/threading/thread_unittest.cc \
+	base/threading/worker_pool_posix_unittest.cc \
+	base/threading/worker_pool_unittest.cc \
+	base/time/pr_time_unittest.cc \
+	base/time/time_unittest.cc \
+	base/timer/hi_res_timer_manager_unittest.cc \
+	base/timer/timer_unittest.cc \
+	base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc \
+	base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc \
+	base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc \
+	base/trace_event/memory_allocator_dump_unittest.cc \
+	base/trace_event/memory_dump_manager_unittest.cc \
+	base/trace_event/process_memory_dump_unittest.cc \
+	base/trace_event/trace_config_unittest.cc \
+	base/trace_event/trace_event_argument_unittest.cc \
+	base/trace_event/trace_event_synthetic_delay_unittest.cc \
+	base/trace_event/trace_event_unittest.cc \
+	base/tracked_objects_unittest.cc \
+	base/tuple_unittest.cc \
+	base/values_unittest.cc \
+	base/version_unittest.cc \
+	base/vlog_unittest.cc \
+	testing/multiprocess_func_list.cc \
+	testrunner.cc \
+
+libchromeCryptoUnittestSrc := \
+	crypto/secure_hash_unittest.cc \
+	crypto/sha2_unittest.cc \
+
+libchromeHostCFlags := -D__ANDROID_HOST__ -DDONT_EMBED_BUILD_METADATA
+
+ifeq ($(HOST_OS),linux)
+libchromeHostSrc := $(libchromeLinuxSrc) \
+	base/allocator/allocator_shim_default_dispatch_to_glibc.cc
+libchromeHostLdFlags :=
+endif
+
+ifeq ($(HOST_OS),darwin)
+libchromeHostSrc := $(libchromeMacSrc)
+libchromeHostCFlags += -D_FILE_OFFSET_BITS=64 -Wno-deprecated-declarations
+libchromeHostLdFlags := \
+	-framework AppKit \
+	-framework CoreFoundation \
+	-framework Foundation \
+	-framework Security
+endif
+
+# libchrome shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome
+LOCAL_SRC_FILES := \
+	$(libchromeCommonSrc) \
+	$(libchromeLinuxSrc) \
+	base/allocator/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc \
+	base/memory/shared_memory_android.cc \
+	base/sys_info_chromeos.cc \
+
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_LDFLAGS := -Wl,-wrap,calloc -Wl,-wrap,free -Wl,-wrap,malloc \
+	-Wl,-wrap,memalign -Wl,-wrap,realloc
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbase
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libgtest_prod
+LOCAL_SHARED_LIBRARIES :=  libbase libevent liblog libcutils
+LOCAL_STATIC_LIBRARIES := libmodpb64 libgtest_prod
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(libchromeExportedCIncludes)
+include $(BUILD_SHARED_LIBRARY)
+
+# libchrome static library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome
+LOCAL_SRC_FILES := \
+	$(libchromeCommonSrc) \
+	$(libchromeLinuxSrc) \
+	base/allocator/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc \
+	base/memory/shared_memory_android.cc \
+	base/sys_info_chromeos.cc \
+
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_LDFLAGS := -Wl,-wrap,calloc -Wl,-wrap,free -Wl,-wrap,malloc \
+	-Wl,-wrap,memalign -Wl,-wrap,realloc
+LOCAL_STATIC_LIBRARIES := libmodpb64 libgtest_prod \
+	libbase libevent liblog libcutils
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := $(LOCAL_STATIC_LIBRARIES)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(libchromeExportedCIncludes)
+include $(BUILD_STATIC_LIBRARY)
+
+# libchrome shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome
+LOCAL_CFLAGS := $(libchromeCommonCFlags) $(libchromeHostCFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(libchromeExportedCIncludes)
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libgtest_prod
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbase
+LOCAL_SHARED_LIBRARIES := libbase libevent
+LOCAL_STATIC_LIBRARIES := libmodpb64 libgtest_prod
+LOCAL_SRC_FILES := \
+	$(libchromeCommonSrc) \
+	$(libchromeHostSrc) \
+
+LOCAL_LDFLAGS := $(libchromeHostLdFlags)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+ifeq ($(local_use_dbus),1)
+
+# libchrome-dbus shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome-dbus
+LOCAL_SRC_FILES := \
+	dbus/bus.cc \
+	dbus/dbus_statistics.cc \
+	dbus/exported_object.cc \
+	dbus/file_descriptor.cc \
+	dbus/message.cc \
+	dbus/object_manager.cc \
+	dbus/object_path.cc \
+	dbus/object_proxy.cc \
+	dbus/property.cc \
+	dbus/scoped_dbus_error.cc \
+	dbus/string_util.cc \
+	dbus/util.cc \
+	dbus/values_util.cc \
+
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_SHARED_LIBRARIES := \
+	libchrome \
+	libdbus \
+
+LOCAL_STATIC_LIBRARIES := libgtest_prod
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(libchromeExportedCIncludes)
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libgtest_prod
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libchrome
+include $(BUILD_SHARED_LIBRARY)
+
+endif  # local_use_dbus == 1
+
+# libchrome-crypto shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome-crypto
+LOCAL_SRC_FILES := \
+	crypto/openssl_util.cc \
+	crypto/random.cc \
+	crypto/secure_hash.cc \
+	crypto/secure_util.cc \
+	crypto/sha2.cc \
+
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags) -Wno-unused-parameter
+LOCAL_CPPFLAGS := $(libchromeCommonCppFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_SHARED_LIBRARIES := \
+	libchrome \
+	libcrypto \
+	libssl \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(libchromeExportedCIncludes)
+include $(BUILD_SHARED_LIBRARY)
+
+# Helpers needed for unit tests.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome_test_helpers
+LOCAL_SHARED_LIBRARIES := libchrome
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags) $(libchromeTestCFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_SRC_FILES := \
+	base/test/simple_test_clock.cc \
+	base/test/simple_test_tick_clock.cc \
+	base/test/test_file_util.cc \
+	base/test/test_file_util_linux.cc \
+	base/test/test_switches.cc \
+	base/test/test_timeouts.cc \
+
+include $(BUILD_STATIC_LIBRARY)
+
+ifeq ($(local_use_dbus),1)
+
+# Helpers needed for D-Bus unit tests.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome_dbus_test_helpers
+LOCAL_SHARED_LIBRARIES := libdbus libchrome-dbus
+LOCAL_STATIC_LIBRARIES := libgmock
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags) $(libchromeTestCFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_SRC_FILES := \
+	dbus/mock_bus.cc \
+	dbus/mock_exported_object.cc \
+	dbus/mock_object_manager.cc \
+	dbus/mock_object_proxy.cc \
+
+include $(BUILD_STATIC_LIBRARY)
+
+endif  # local_use_dbus == 1
+
+# Helpers needed for unit tests (for host).
+# ========================================================
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome_test_helpers-host
+LOCAL_SHARED_LIBRARIES := libchrome
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags) $(libchromeTestCFlags)
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_SRC_FILES := base/test/simple_test_clock.cc
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# Host unit tests. Run (from repo root) with:
+# ./out/host/<arch>/bin/libchrome_test
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome_test
+LOCAL_SRC_FILES := $(libchromeCommonUnittestSrc)
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags) $(libchromeTestCFlags) $(libchromeHostCFlags) -DUNIT_TEST
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_SHARED_LIBRARIES := libchrome libevent
+LOCAL_STATIC_LIBRARIES := libgmock_host libgtest_host
+LOCAL_LDLIBS := -lrt
+include $(BUILD_HOST_NATIVE_TEST)
+endif
+
+# Native unit tests. Run with:
+# adb shell /data/nativetest/libchrome_test/libchrome_test
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libchrome_test
+LOCAL_SRC_FILES := $(libchromeCryptoUnittestSrc) $(libchromeCommonUnittestSrc)
+LOCAL_CPP_EXTENSION := $(libchromeCommonCppExtension)
+LOCAL_CFLAGS := $(libchromeCommonCFlags) $(libchromeTestCFlags) -DUNIT_TEST -DDONT_EMBED_BUILD_METADATA
+LOCAL_CLANG := $(libchromeUseClang)
+LOCAL_C_INCLUDES := $(libchromeCommonCIncludes)
+LOCAL_SHARED_LIBRARIES := libchrome libchrome-crypto libevent
+LOCAL_STATIC_LIBRARIES := libgmock libgtest
+include $(BUILD_NATIVE_TEST)
diff --git a/libchrome/MODULE_LICENSE_BSD b/libchrome/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libchrome/MODULE_LICENSE_BSD
diff --git a/libchrome/NOTICE b/libchrome/NOTICE
new file mode 100644
index 0000000..972bb2e
--- /dev/null
+++ b/libchrome/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/libchrome/SConstruct b/libchrome/SConstruct
new file mode 100644
index 0000000..72e022e
--- /dev/null
+++ b/libchrome/SConstruct
@@ -0,0 +1,540 @@
+# -*- python -*-
+
+# Copyright 2014 The Chromium OS 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 to build the libchrome package for Chrome OS:
+# https://www.chromium.org/chromium-os/packages/libchrome
+
+import os
+
+env = Environment()
+
+BASE_VER = os.environ.get('BASE_VER', '0')
+PKG_CONFIG = os.environ.get('PKG_CONFIG', 'pkg-config')
+CHROME_INCLUDE_PATH = os.environ.get('CHROME_INCLUDE_PATH', '.')
+
+# This block will need updating whenever libchrome gets updated. The order of
+# the libs below doesn't matter (as scons will take care of building things in
+# the required order).  The split between them is purely to reduce excess
+# linking of third-party libraries, i.e. 'core' should require only a minimal
+# set of libraries, and other third-party libraries should get a unique 'xxx'
+# name.
+base_name = 'base'
+base_libs = [
+  {
+    'name' : 'core',
+    'sources' : """
+                allocator/allocator_extension.cc
+                allocator/allocator_shim.cc
+                allocator/allocator_shim_default_dispatch_to_glibc.cc
+                at_exit.cc
+                base64.cc
+                base64url.cc
+                base_switches.cc
+                bind_helpers.cc
+                build_time.cc
+                callback_helpers.cc
+                callback_internal.cc
+                command_line.cc
+                cpu.cc
+                debug/alias.cc
+                debug/debugger.cc
+                debug/debugger_posix.cc
+                debug/stack_trace.cc
+                debug/stack_trace_posix.cc
+                debug/task_annotator.cc
+                environment.cc
+                files/file.cc
+                files/file_enumerator.cc
+                files/file_enumerator_posix.cc
+                files/file_path.cc
+                files/file_path_constants.cc
+                files/file_path_watcher.cc
+                files/file_path_watcher_linux.cc
+                files/file_posix.cc
+                files/file_tracing.cc
+                files/file_util.cc
+                files/file_util_linux.cc
+                files/file_util_posix.cc
+                files/important_file_writer.cc
+                files/memory_mapped_file.cc
+                files/memory_mapped_file_posix.cc
+                files/scoped_file.cc
+                files/scoped_temp_dir.cc
+                guid.cc
+                hash.cc
+                json/json_file_value_serializer.cc
+                json/json_parser.cc
+                json/json_reader.cc
+                json/json_string_value_serializer.cc
+                json/json_value_converter.cc
+                json/json_writer.cc
+                json/string_escape.cc
+                lazy_instance.cc
+                location.cc
+                logging.cc
+                md5.cc
+                memory/aligned_memory.cc
+                memory/ref_counted.cc
+                memory/ref_counted_memory.cc
+                memory/shared_memory_posix.cc
+                memory/singleton.cc
+                memory/weak_ptr.cc
+                message_loop/incoming_task_queue.cc
+                message_loop/message_loop.cc
+                message_loop/message_loop_task_runner.cc
+                message_loop/message_pump.cc
+                message_loop/message_pump_default.cc
+                message_loop/message_pump_glib.cc
+                message_loop/message_pump_libevent.cc
+                metrics/bucket_ranges.cc
+                metrics/field_trial.cc
+                metrics/metrics_hashes.cc
+                metrics/histogram_base.cc
+                metrics/histogram.cc
+                metrics/histogram_samples.cc
+                metrics/histogram_snapshot_manager.cc
+                metrics/persistent_histogram_allocator.cc
+                metrics/persistent_memory_allocator.cc
+                metrics/persistent_sample_map.cc
+                metrics/sample_map.cc
+                metrics/sample_vector.cc
+                metrics/sparse_histogram.cc
+                metrics/statistics_recorder.cc
+                pending_task.cc
+                pickle.cc
+                posix/file_descriptor_shuffle.cc
+                posix/global_descriptors.cc
+                posix/safe_strerror.cc
+                posix/unix_domain_socket_linux.cc
+                process/internal_linux.cc
+                process/kill.cc
+                process/kill_posix.cc
+                process/launch.cc
+                process/launch_posix.cc
+                process/process_handle_linux.cc
+                process/process_iterator.cc
+                process/process_iterator_linux.cc
+                process/process_handle_posix.cc
+                process/process_metrics.cc
+                process/process_metrics_linux.cc
+                process/process_metrics_posix.cc
+                process/process_posix.cc
+                profiler/scoped_profile.cc
+                profiler/scoped_tracker.cc
+                profiler/tracked_time.cc
+                rand_util.cc
+                rand_util_posix.cc
+                run_loop.cc
+                sequence_checker_impl.cc
+                sequenced_task_runner.cc
+                sha1_portable.cc
+                strings/pattern.cc
+                strings/safe_sprintf.cc
+                strings/string16.cc
+                strings/string_number_conversions.cc
+                strings/string_piece.cc
+                strings/stringprintf.cc
+                strings/string_split.cc
+                strings/string_util.cc
+                strings/string_util_constants.cc
+                strings/sys_string_conversions_posix.cc
+                strings/utf_string_conversions.cc
+                strings/utf_string_conversion_utils.cc
+                synchronization/cancellation_flag.cc
+                synchronization/condition_variable_posix.cc
+                synchronization/lock.cc
+                synchronization/lock_impl_posix.cc
+                synchronization/read_write_lock_posix.cc
+                synchronization/waitable_event_posix.cc
+                synchronization/waitable_event_watcher_posix.cc
+                sync_socket_posix.cc
+                sys_info.cc
+                sys_info_chromeos.cc
+                sys_info_linux.cc
+                sys_info_posix.cc
+                task_runner.cc
+                task/cancelable_task_tracker.cc
+                task_scheduler/scheduler_lock_impl.cc
+                task_scheduler/sequence.cc
+                task_scheduler/sequence_sort_key.cc
+                task_scheduler/task.cc
+                task_scheduler/task_traits.cc
+                third_party/icu/icu_utf.cc
+                third_party/nspr/prtime.cc
+                threading/non_thread_safe_impl.cc
+                threading/platform_thread_internal_posix.cc
+                threading/platform_thread_linux.cc
+                threading/platform_thread_posix.cc
+                threading/post_task_and_reply_impl.cc
+                threading/sequenced_task_runner_handle.cc
+                threading/sequenced_worker_pool.cc
+                threading/simple_thread.cc
+                threading/thread.cc
+                threading/thread_checker_impl.cc
+                threading/thread_collision_warner.cc
+                threading/thread_id_name_manager.cc
+                threading/thread_local_posix.cc
+                threading/thread_local_storage.cc
+                threading/thread_local_storage_posix.cc
+                threading/thread_restrictions.cc
+                threading/thread_task_runner_handle.cc
+                threading/worker_pool.cc
+                threading/worker_pool_posix.cc
+                timer/elapsed_timer.cc
+                timer/timer.cc
+                time/clock.cc
+                time/default_clock.cc
+                time/default_tick_clock.cc
+                time/tick_clock.cc
+                time/time.cc
+                time/time_posix.cc
+                trace_event/heap_profiler_allocation_context.cc
+                trace_event/heap_profiler_allocation_context_tracker.cc
+                trace_event/heap_profiler_allocation_register.cc
+                trace_event/heap_profiler_allocation_register_posix.cc
+                trace_event/heap_profiler_heap_dump_writer.cc
+                trace_event/heap_profiler_stack_frame_deduplicator.cc
+                trace_event/heap_profiler_type_name_deduplicator.cc
+                trace_event/malloc_dump_provider.cc
+                trace_event/memory_allocator_dump.cc
+                trace_event/memory_allocator_dump_guid.cc
+                trace_event/memory_dump_manager.cc
+                trace_event/memory_dump_request_args.cc
+                trace_event/memory_dump_session_state.cc
+                trace_event/memory_infra_background_whitelist.cc
+                trace_event/process_memory_dump.cc
+                trace_event/process_memory_maps.cc
+                trace_event/process_memory_totals.cc
+                trace_event/trace_buffer.cc
+                trace_event/trace_config.cc
+                trace_event/trace_event_argument.cc
+                trace_event/trace_event_impl.cc
+                trace_event/trace_event_memory_overhead.cc
+                trace_event/trace_event_synthetic_delay.cc
+                trace_event/trace_log.cc
+                trace_event/trace_log_constants.cc
+                trace_event/trace_sampling_thread.cc
+                tracked_objects.cc
+                tracking_info.cc
+                values.cc
+                version.cc
+                vlog.cc
+                """,
+    'prefix' : 'base',
+    'libs' : 'pthread rt libmodp_b64',
+    'pc_libs' : 'glib-2.0 libevent',
+  },
+  {
+    'name' : 'dl',
+    'sources' : """
+                native_library_posix.cc
+                """,
+    'prefix' : 'base',
+    'libs' : 'dl',
+    'pc_libs' : '',
+  },
+  {
+    'name' : 'dbus',
+    'sources' : """
+                bus.cc
+                dbus_statistics.cc
+                exported_object.cc
+                file_descriptor.cc
+                message.cc
+                object_manager.cc
+                object_path.cc
+                object_proxy.cc
+                property.cc
+                scoped_dbus_error.cc
+                string_util.cc
+                util.cc
+                values_util.cc
+                """,
+    'prefix' : 'dbus',
+    'libs' : '',
+    'pc_libs' : 'dbus-1 protobuf-lite',
+  },
+  {
+    'name' : 'timers',
+    'sources' : """
+                alarm_timer_chromeos.cc
+                """,
+    'prefix' : 'components/timers',
+    'libs' : '',
+    'pc_libs' : '',
+  },
+  {
+    'name' : 'crypto',
+    'sources' : """
+                hmac.cc
+                hmac_nss.cc
+                nss_key_util.cc
+                nss_util.cc
+                openssl_util.cc
+                p224.cc
+                p224_spake.cc
+                random.cc
+                rsa_private_key.cc
+                rsa_private_key_nss.cc
+                scoped_test_nss_db.cc
+                secure_hash.cc
+                secure_util.cc
+                sha2.cc
+                signature_creator_nss.cc
+                signature_verifier_nss.cc
+                symmetric_key_nss.cc
+                third_party/nss/rsawrapr.c
+                third_party/nss/sha512.cc
+                """,
+    'prefix' : 'crypto',
+    'libs' : '%s-dl-%s' % (base_name, BASE_VER),
+    'pc_libs' : 'nss openssl',
+  },
+  {
+    'name' : 'sandbox',
+    'sources' : """
+                linux/bpf_dsl/bpf_dsl.cc
+                linux/bpf_dsl/codegen.cc
+                linux/bpf_dsl/dump_bpf.cc
+                linux/bpf_dsl/policy.cc
+                linux/bpf_dsl/policy_compiler.cc
+                linux/bpf_dsl/syscall_set.cc
+                linux/bpf_dsl/verifier.cc
+                linux/seccomp-bpf/die.cc
+                linux/seccomp-bpf/sandbox_bpf.cc
+                linux/seccomp-bpf/syscall.cc
+                linux/seccomp-bpf/trap.cc
+
+                linux/seccomp-bpf-helpers/baseline_policy.cc
+                linux/seccomp-bpf-helpers/sigsys_handlers.cc
+                linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+                linux/seccomp-bpf-helpers/syscall_sets.cc
+
+                linux/services/init_process_reaper.cc
+                linux/services/proc_util.cc
+                linux/services/resource_limits.cc
+                linux/services/scoped_process.cc
+                linux/services/syscall_wrappers.cc
+                linux/services/thread_helpers.cc
+                linux/services/yama.cc
+                linux/syscall_broker/broker_channel.cc
+                linux/syscall_broker/broker_client.cc
+                linux/syscall_broker/broker_file_permission.cc
+                linux/syscall_broker/broker_host.cc
+                linux/syscall_broker/broker_policy.cc
+                linux/syscall_broker/broker_process.cc
+
+                linux/services/credentials.cc
+                linux/services/namespace_sandbox.cc
+                linux/services/namespace_utils.cc
+                """,
+    'prefix' : 'sandbox',
+    'libs' : '',
+    'pc_libs' : '',
+  },
+]
+
+env.Append(
+  CPPPATH=['files'],
+  CCFLAGS=['-g']
+)
+for key in Split('CC CXX AR RANLIB LD NM CFLAGS CXXFLAGS LDFLAGS'):
+  value = os.environ.get(key)
+  if value:
+    env[key] = Split(value)
+if os.environ.has_key('CPPFLAGS'):
+  env['CCFLAGS'] += Split(os.environ['CPPFLAGS'])
+
+env['CCFLAGS'] += ['-DOS_CHROMEOS',
+                   '-DUSE_NSS_CERTS',
+                   '-DUSE_SYSTEM_LIBEVENT',
+                   '-DNO_TCMALLOC',
+                   '-fPIC',
+                   '-fno-exceptions',
+                   '-Wall',
+                   '-Werror',
+                   '-Wno-deprecated-register',
+                   '-Wno-narrowing',
+                   '-Wno-psabi',
+                   '-Wno-unused-local-typedefs',
+                   # Various #defines are hardcoded near the top of
+                   # build_config.h to ensure that they'll be set both when
+                   # libchrome is built and when other packages include
+                   # libchrome's headers.
+                   '-I%s' % CHROME_INCLUDE_PATH]
+
+env.Append(
+  CXXFLAGS=['-std=c++11']
+)
+
+# Flags for clang taken from build/common.gypi in the clang==1 section.
+CLANG_FLAGS = (
+  '-Wno-char-subscripts',
+)
+
+env['CCFLAGS'] += ['-Xclang-only=%s' % x for x in CLANG_FLAGS]
+
+# Fix issue with scons not passing some vars through the environment.
+for key in Split('PKG_CONFIG SYSROOT'):
+  if os.environ.has_key(key):
+    env['ENV'][key] = os.environ[key]
+
+all_base_libs = []
+all_pc_libs = ''
+all_libs = []
+all_scons_libs = []
+
+# Build all the shared libraries.
+for lib in base_libs:
+  pc_libs = lib['pc_libs'].replace('${bslot}', BASE_VER)
+  all_pc_libs += ' ' + pc_libs
+
+  libs = Split(lib['libs'].replace('${bslot}', BASE_VER))
+  all_libs += libs
+
+  name = '%s-%s-%s' % (base_name, lib['name'], BASE_VER)
+  all_base_libs += [name]
+  corename = '%s-core-%s' % (base_name, BASE_VER)
+  # Automatically link the sub-libs against the main core lib.
+  # This is to keep from having to explicitly mention it in the
+  # table above (i.e. lazy).
+  if name != corename:
+    libs += [corename]
+
+  e = env.Clone()
+  e.Append(
+    LIBS = Split(libs),
+    LIBPATH = ['.'],
+    LINKFLAGS = ['-Wl,--as-needed', '-Wl,-z,defs',
+                 '-Wl,-soname,lib%s.so' % name],
+  )
+  if pc_libs:
+    e.ParseConfig(PKG_CONFIG + ' --cflags --libs %s' % pc_libs)
+
+  # Prepend prefix to source filenames.
+  sources = [os.path.join(lib['prefix'], x) for x in Split(lib['sources'])]
+
+  all_scons_libs += [ e.SharedLibrary(name, sources) ]
+
+
+# Build a static library of mocks for unittests to link against.
+# Being static allows us to mask this library out of the image.
+
+all_base_test_libs = []
+all_test_pc_libs = ''
+all_test_libs = []
+
+test_libs = [
+  {
+    'name': 'base_test_support',
+    'sources': """
+               simple_test_clock.cc
+               simple_test_tick_clock.cc
+               test_file_util.cc
+               test_file_util_linux.cc
+               test_switches.cc
+               test_timeouts.cc
+               """,
+    'prefix': 'base/test',
+    'libs': '',
+    'pc_libs': '',
+  },
+  {
+    'name': 'dbus_test_support',
+    'sources': """
+               mock_bus.cc
+               mock_exported_object.cc
+               mock_object_manager.cc
+               mock_object_proxy.cc
+               """,
+    'prefix': 'dbus',
+    'libs': '',  # TODO(wiley) what should go here?
+    'pc_libs': 'dbus-1 protobuf-lite',
+  },
+  {
+    'name': 'timer_test_support',
+    'sources': """
+               mock_timer.cc
+               """,
+    'prefix': 'base/timer',
+    'libs': '',
+    'pc_libs': '',
+  },
+]
+
+for lib in test_libs:
+  pc_libs = lib['pc_libs'].replace('${bslot}', BASE_VER)
+  all_test_pc_libs += ' ' + pc_libs
+
+  libs = Split(lib['libs'].replace('${bslot}', BASE_VER))
+  all_test_libs += libs
+
+  name = '%s-%s-%s' % (base_name, lib['name'], BASE_VER)
+  all_base_test_libs += [name]
+
+  static_env = env.Clone()
+  if pc_libs:
+    static_env.ParseConfig(PKG_CONFIG + ' --cflags --libs %s' % pc_libs)
+  sources = [os.path.join(lib['prefix'], x)
+             for x in Split(lib['sources'])]
+  static_env.StaticLibrary(name, sources)
+
+# Build the random text files (pkg-config and linker script).
+
+def lib_list(libs):
+  return ' '.join(['-l' + l for l in libs])
+
+prod_subst_dict = {
+  '@BSLOT@': BASE_VER,
+  '@PRIVATE_PC@': all_pc_libs,
+  '@BASE_LIBS@': lib_list(all_base_libs),
+  '@LIBS@': lib_list(all_libs),
+  '@NAME@': 'libchrome',
+  '@PKG_CFG_NAME@': 'libchrome-%s.pc' % BASE_VER,
+  '@LIB_NAME@': 'libbase-%s.so' % BASE_VER,
+  '@DESCRIPTION@': 'chrome base library',
+  # scons, in its infinite wisdom sees fit to expand this string if
+  # if we don't escape the $.
+  '@TARGET_LIB@': 'base-$${bslot}',
+}
+
+# Similarly, build text files related to the test libraries.
+test_subst_dict = {
+  '@BSLOT@': BASE_VER,
+  '@PRIVATE_PC@': all_test_pc_libs,
+  '@BASE_LIBS@': lib_list(all_base_test_libs),
+  '@LIBS@': lib_list(all_test_libs),
+  '@NAME@': 'libchrome-test',
+  '@PKG_CFG_NAME@': 'libchrome-test-%s.pc' % BASE_VER,
+  '@LIB_NAME@': 'libbase-test-%s.a' % BASE_VER,
+  '@DESCRIPTION@': 'chrome base test library',
+  # scons, in its infinite wisdom sees fit to expand this string if
+  # if we don't escape the $.
+  '@TARGET_LIB@': 'base-test-$${bslot}',
+}
+
+pc_file_contents = """
+prefix=/usr
+includedir=${prefix}/include
+bslot=@BSLOT@
+
+Name: @NAME@
+Description: @DESCRIPTION@
+Version: ${bslot}
+Requires:
+Requires.private: @PRIVATE_PC@
+Libs: -l@TARGET_LIB@
+Libs.private: @BASE_LIBS@ @LIBS@
+Cflags: -I${includedir}/@TARGET_LIB@ -Wno-c++11-extensions -Wno-unused-local-typedefs -DBASE_VER=${bslot}
+"""
+
+# https://sourceware.org/binutils/docs/ld/Scripts.html
+so_file_contents = """GROUP ( AS_NEEDED ( @BASE_LIBS@ ) )"""
+
+for subst_dict in (test_subst_dict, prod_subst_dict):
+  env = Environment(tools=['textfile'], SUBST_DICT=subst_dict)
+  env.Substfile(subst_dict['@LIB_NAME@'], [Value(so_file_contents)])
+  env.Substfile(subst_dict['@PKG_CFG_NAME@'], [Value(pc_file_contents)])
diff --git a/libchrome/base/BUILD.gn b/libchrome/base/BUILD.gn
new file mode 100644
index 0000000..c147989
--- /dev/null
+++ b/libchrome/base/BUILD.gn
@@ -0,0 +1,2434 @@
+# 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.
+
+# HOW TO WRITE CONDITIONALS IN THIS FILE
+# ======================================
+#
+# In many other places, one would write a conditional that expresses all the
+# cases when a source file is used or unused, and then either add or subtract
+# it from the sources list in that case
+#
+# Since base includes so many low-level things that vary widely and
+# unpredictably for the various build types, we prefer a slightly different
+# style. Instead, there are big per-platform blocks of inclusions and
+# exclusions. If a given file has an inclusion or exclusion rule that applies
+# for multiple conditions, perfer to duplicate it in both lists. This makes it
+# a bit easier to see which files apply in which cases rather than having a
+# huge sequence of random-looking conditionals.
+
+import("//build/buildflag_header.gni")
+import("//build/config/allocator.gni")
+import("//build/config/chromecast_build.gni")
+import("//build/config/compiler/compiler.gni")
+import("//build/config/nacl/config.gni")
+import("//build/config/sysroot.gni")
+import("//build/config/ui.gni")
+import("//build/nocompile.gni")
+import("//testing/test.gni")
+
+declare_args() {
+  # Override this value to give a specific build date.
+  # See //base/build_time.cc and //build/write_build_date_header.py for more
+  # details and the expected format.
+  override_build_date = "N/A"
+}
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+if (is_win) {
+  import("//build/config/win/visual_studio_version.gni")
+}
+
+config("base_flags") {
+  if (is_clang) {
+    cflags = [
+      # Don't die on dtoa code that uses a char as an array index.
+      # This is required solely for base/third_party/dmg_fp/dtoa_wrapper.cc.
+      "-Wno-char-subscripts",
+    ]
+  }
+}
+
+config("base_implementation") {
+  defines = [ "BASE_IMPLEMENTATION" ]
+  configs = [ "//build/config/compiler:wexit_time_destructors" ]
+}
+
+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",
+    ]
+  }
+}
+
+if (is_nacl_nonsfi) {
+  # Must be in a config because of how GN orders flags (otherwise -Wall will
+  # appear after this, and turn it back on).
+  config("nacl_nonsfi_warnings") {
+    # file_util_posix.cc contains a function which is not
+    # being used by nacl_helper_nonsfi.
+    cflags = [ "-Wno-unused-function" ]
+  }
+}
+
+if (is_nacl) {
+  # None of the files apply to nacl, and we can't make an empty static library.
+  group("base_paths") {
+  }
+} else {
+  static_library("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 || is_ios) {
+      sources -= [ "base_paths_posix.cc" ]
+    }
+
+    configs += [ ":base_implementation" ]
+
+    visibility = [ ":base" ]
+  }
+}
+
+if (is_android) {
+  config("android_system_libs") {
+    libs = [ "log" ]  # Used by logging.cc.
+  }
+}
+
+# Base and everything it depends on should be a static library rather than
+# a source set. Base is more of a "library" in the classic sense in that many
+# small parts of it are used in many different contexts. This combined with a
+# few static initializers floating around means that dead code stripping
+# still leaves a lot of code behind that isn't always used. For example, this
+# saves more than 40K for a smaller target like chrome_elf.
+#
+# Use static libraries for the helper stuff as well like //base/debug since
+# those things refer back to base code, which will force base compilation units
+# to be linked in where they wouldn't have otherwise. This does not include
+# test code (test support and anything in the test directory) which should use
+# source_set as is recommended for GN targets).
+component("base") {
+  if (is_nacl_nonsfi) {
+    # TODO(phosek) bug 570839: If field_trial.cc is in a static library,
+    # nacl_helper_nonsfi doesn't link properly on Linux in debug builds. The
+    # reasons for this seem to involve obscure toolchain bugs. This should be
+    # fixed and this target should always be a static_library in the
+    # non-component case.
+    static_component_type = "source_set"
+  }
+
+  sources = [
+    "allocator/allocator_check.cc",
+    "allocator/allocator_check.h",
+    "allocator/allocator_extension.cc",
+    "allocator/allocator_extension.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/callback_android.cc",
+    "android/callback_android.h",
+    "android/command_line_android.cc",
+    "android/command_line_android.h",
+    "android/content_uri_utils.cc",
+    "android/content_uri_utils.h",
+    "android/context_utils.cc",
+    "android/context_utils.h",
+    "android/cpu_features.cc",
+    "android/cxa_demangle_stub.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_portable.h",
+    "atomicops_internals_x86_msvc.h",
+    "auto_reset.h",
+    "barrier_closure.cc",
+    "barrier_closure.h",
+    "base64.cc",
+    "base64.h",
+    "base64url.cc",
+    "base64url.h",
+    "base_export.h",
+    "base_switches.h",
+    "big_endian.cc",
+    "big_endian.h",
+    "bind.h",
+    "bind_helpers.cc",
+    "bind_helpers.h",
+    "bind_internal.h",
+    "bit_cast.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/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/close_handle_hook_win.cc",
+    "debug/close_handle_hook_win.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 "debug/allocator" target,
+    # but this target does not depend on "debug/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",
+    "feature_list.cc",
+    "feature_list.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",
+    "hash.cc",
+    "hash.h",
+    "id_map.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/ns_error_util.h",
+    "ios/ns_error_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",
+    "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/call_with_eh_frame.cc",
+    "mac/call_with_eh_frame.h",
+    "mac/call_with_eh_frame_asm.S",
+    "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/mac_logging.h",
+    "mac/mac_logging.mm",
+    "mac/mac_util.h",
+    "mac/mac_util.mm",
+    "mac/mach_logging.cc",
+    "mac/mach_logging.h",
+    "mac/mach_port_broker.h",
+    "mac/mach_port_broker.mm",
+    "mac/mach_port_util.cc",
+    "mac/mach_port_util.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_dispatch_object.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_nsobject.h",
+    "mac/scoped_nsobject.mm",
+    "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",
+    "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/free_deleter.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/ptr_util.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_vector.h",
+    "memory/shared_memory.h",
+    "memory/shared_memory_android.cc",
+    "memory/shared_memory_handle.h",
+    "memory/shared_memory_handle_mac.cc",
+    "memory/shared_memory_handle_win.cc",
+    "memory/shared_memory_mac.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_task_runner.cc",
+    "message_loop/message_loop_task_runner.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",
+    "metrics/bucket_ranges.cc",
+    "metrics/bucket_ranges.h",
+    "metrics/field_trial.cc",
+    "metrics/field_trial.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/metrics_hashes.cc",
+    "metrics/metrics_hashes.h",
+    "metrics/persistent_histogram_allocator.cc",
+    "metrics/persistent_histogram_allocator.h",
+    "metrics/persistent_memory_allocator.cc",
+    "metrics/persistent_memory_allocator.h",
+    "metrics/persistent_sample_map.cc",
+    "metrics/persistent_sample_map.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",
+    "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",
+    "optional.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",
+    "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",
+    "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/port_provider_mac.cc",
+    "process/port_provider_mac.h",
+    "process/process.h",
+    "process/process_handle.cc",
+
+    #"process/process_handle_freebsd.cc",  # Unused in Chromium build.
+    "process/process_handle_linux.cc",
+    "process/process_handle_mac.cc",
+
+    #"process/process_handle_openbsd.cc",  # Unused in Chromium build.
+    "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",  # Unused in Chromium build.
+    "process/process_iterator_linux.cc",
+    "process/process_iterator_mac.cc",
+
+    #"process/process_iterator_openbsd.cc",  # Unused in Chromium build.
+    "process/process_iterator_win.cc",
+    "process/process_linux.cc",
+    "process/process_metrics.cc",
+    "process/process_metrics.h",
+
+    #"process/process_metrics_freebsd.cc",  # Unused in Chromium build.
+    "process/process_metrics_ios.cc",
+    "process/process_metrics_linux.cc",
+    "process/process_metrics_mac.cc",
+
+    #"process/process_metrics_openbsd.cc",  # Unused in Chromium build.
+    "process/process_metrics_posix.cc",
+    "process/process_metrics_win.cc",
+    "process/process_posix.cc",
+    "process/process_win.cc",
+    "profiler/native_stack_sampler.cc",
+    "profiler/native_stack_sampler.h",
+    "profiler/native_stack_sampler_posix.cc",
+    "profiler/native_stack_sampler_win.cc",
+    "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/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.cc",
+    "sha1.h",
+    "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/pattern.cc",
+    "strings/pattern.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/read_write_lock.h",
+    "synchronization/read_write_lock_nacl.cc",
+    "synchronization/read_write_lock_posix.cc",
+    "synchronization/read_write_lock_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",  # Unused in Chromium build.
+    "sys_info_ios.mm",
+    "sys_info_linux.cc",
+    "sys_info_mac.mm",
+
+    #"sys_info_openbsd.cc",  # Unused in Chromium build.
+    "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",
+    "task_scheduler/delayed_task_manager.cc",
+    "task_scheduler/delayed_task_manager.h",
+    "task_scheduler/priority_queue.cc",
+    "task_scheduler/priority_queue.h",
+    "task_scheduler/scheduler_lock.h",
+    "task_scheduler/scheduler_lock_impl.cc",
+    "task_scheduler/scheduler_lock_impl.h",
+    "task_scheduler/scheduler_service_thread.cc",
+    "task_scheduler/scheduler_service_thread.h",
+    "task_scheduler/scheduler_worker.cc",
+    "task_scheduler/scheduler_worker.h",
+    "task_scheduler/scheduler_worker_pool.h",
+    "task_scheduler/scheduler_worker_pool_impl.cc",
+    "task_scheduler/scheduler_worker_pool_impl.h",
+    "task_scheduler/scheduler_worker_stack.cc",
+    "task_scheduler/scheduler_worker_stack.h",
+    "task_scheduler/sequence.cc",
+    "task_scheduler/sequence.h",
+    "task_scheduler/sequence_sort_key.cc",
+    "task_scheduler/sequence_sort_key.h",
+    "task_scheduler/task.cc",
+    "task_scheduler/task.h",
+    "task_scheduler/task_scheduler.cc",
+    "task_scheduler/task_scheduler.h",
+    "task_scheduler/task_scheduler_impl.cc",
+    "task_scheduler/task_scheduler_impl.h",
+    "task_scheduler/task_tracker.cc",
+    "task_scheduler/task_tracker.h",
+    "task_scheduler/task_traits.cc",
+    "task_scheduler/task_traits.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",
+    "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_task_runner_handle.cc",
+    "threading/sequenced_task_runner_handle.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/thread_task_runner_handle.cc",
+    "threading/thread_task_runner_handle.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",
+    "trace_event/blame_context.cc",
+    "trace_event/blame_context.h",
+    "trace_event/common/trace_event_common.h",
+    "trace_event/heap_profiler.h",
+    "trace_event/heap_profiler_allocation_context.cc",
+    "trace_event/heap_profiler_allocation_context.h",
+    "trace_event/heap_profiler_allocation_context_tracker.cc",
+    "trace_event/heap_profiler_allocation_context_tracker.h",
+    "trace_event/heap_profiler_allocation_register.cc",
+    "trace_event/heap_profiler_allocation_register.h",
+    "trace_event/heap_profiler_allocation_register_posix.cc",
+    "trace_event/heap_profiler_allocation_register_win.cc",
+    "trace_event/heap_profiler_heap_dump_writer.cc",
+    "trace_event/heap_profiler_heap_dump_writer.h",
+    "trace_event/heap_profiler_stack_frame_deduplicator.cc",
+    "trace_event/heap_profiler_stack_frame_deduplicator.h",
+    "trace_event/heap_profiler_type_name_deduplicator.cc",
+    "trace_event/heap_profiler_type_name_deduplicator.h",
+    "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.cc",
+    "trace_event/memory_dump_request_args.h",
+    "trace_event/memory_dump_session_state.cc",
+    "trace_event/memory_dump_session_state.h",
+    "trace_event/memory_infra_background_whitelist.cc",
+    "trace_event/memory_infra_background_whitelist.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_totals.cc",
+    "trace_event/process_memory_totals.h",
+    "trace_event/trace_buffer.cc",
+    "trace_event/trace_buffer.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_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_log.cc",
+    "trace_event/trace_log.h",
+    "trace_event/trace_log_constants.cc",
+    "trace_event/trace_sampling_thread.cc",
+    "trace_event/trace_sampling_thread.h",
+    "trace_event/tracing_agent.cc",
+    "trace_event/tracing_agent.h",
+    "trace_event/winheap_dump_provider_win.cc",
+    "trace_event/winheap_dump_provider_win.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/object_watcher.cc",
+    "win/object_watcher.h",
+    "win/process_startup_helper.cc",
+    "win/process_startup_helper.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/wait_chain.cc",
+    "win/wait_chain.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",
+  ]
+
+  defines = []
+  data = []
+
+  configs += [
+    ":base_flags",
+    ":base_implementation",
+    "//base/allocator:allocator_shim_define",  # for allocator_check.cc.
+    "//build/config:precompiled_headers",
+  ]
+
+  deps = [
+    "//base/allocator",
+    "//base/allocator:features",
+    "//base/third_party/dynamic_annotations",
+    "//third_party/modp_b64",
+  ]
+
+  public_deps = [
+    ":base_paths",
+    ":base_static",
+    ":build_date",
+    ":debugging_flags",
+  ]
+
+  # Needed for <atomic> if using newer C++ library than sysroot
+  if (!use_sysroot && (is_android || is_linux)) {
+    libs = [ "atomic" ]
+  }
+
+  if (use_experimental_allocator_shim) {
+    # The allocator shim is part of the base API. This is to allow clients of
+    # base should to install hooks into the allocator path.
+    public_deps += [ "//base/allocator:unified_allocator_shim" ]
+  }
+
+  # Allow more direct string conversions on platforms with native utf8
+  # strings
+  if (is_mac || is_ios || is_chromeos || is_chromecast) {
+    defines += [ "SYSTEM_NATIVE_UTF8" ]
+  }
+
+  # Android.
+  if (is_android) {
+    sources -= [
+      "debug/stack_trace_posix.cc",
+      "power_monitor/power_monitor_device_source_posix.cc",
+    ]
+
+    # Android uses some Linux sources, put those back.
+    set_sources_assignment_filter([])
+    sources += [
+      "debug/proc_maps_linux.cc",
+      "files/file_path_watcher_linux.cc",
+      "posix/unix_domain_socket_linux.cc",
+      "process/internal_linux.cc",
+      "process/memory_linux.cc",
+      "process/process_handle_linux.cc",
+      "process/process_iterator_linux.cc",
+      "process/process_metrics_linux.cc",
+      "sys_info_linux.cc",
+      "trace_event/malloc_dump_provider.cc",
+      "trace_event/malloc_dump_provider.h",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    deps += [
+      ":base_jni_headers",
+      "//third_party/android_tools:cpu_features",
+      "//third_party/ashmem",
+    ]
+
+    # Needs to be a public config so that dependent targets link against it as
+    # well when doing a component build.
+    public_configs = [ ":android_system_libs" ]
+  }
+
+  # Chromeos.
+  if (is_chromeos) {
+    sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
+  }
+
+  # NaCl.
+  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",
+      "process/process_metrics_nacl.cc",
+      "sync_socket_nacl.cc",
+      "threading/platform_thread_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    sources -= [
+      "cpu.cc",
+      "debug/crash_logging.cc",
+      "debug/crash_logging.h",
+      "debug/stack_trace.cc",
+      "debug/stack_trace_posix.cc",
+      "files/file_enumerator_posix.cc",
+      "files/file_proxy.cc",
+      "files/file_util_proxy.cc",
+      "files/important_file_writer.cc",
+      "files/important_file_writer.h",
+      "files/scoped_temp_dir.cc",
+      "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/shared_memory_posix.cc",
+      "native_library_posix.cc",
+      "path_service.cc",
+      "process/kill.cc",
+      "process/kill.h",
+      "process/memory.cc",
+      "process/memory.h",
+      "process/process_iterator.cc",
+      "process/process_iterator.h",
+      "process/process_metrics.cc",
+      "process/process_metrics_posix.cc",
+      "process/process_posix.cc",
+      "scoped_native_library.cc",
+      "sync_socket_posix.cc",
+      "synchronization/read_write_lock_posix.cc",
+      "sys_info.cc",
+      "sys_info_posix.cc",
+      "trace_event/trace_event_system_stats_monitor.cc",
+    ]
+
+    if (is_nacl_nonsfi) {
+      set_sources_assignment_filter([])
+      sources += [ "posix/unix_domain_socket_linux.cc" ]
+      set_sources_assignment_filter(sources_assignment_filter)
+      sources -= [ "rand_util_nacl.cc" ]
+      configs += [ ":nacl_nonsfi_warnings" ]
+    } else {
+      sources -= [
+        "files/file_util.cc",
+        "files/file_util.h",
+        "files/file_util_posix.cc",
+        "json/json_file_value_serializer.cc",
+        "json/json_file_value_serializer.h",
+        "message_loop/message_pump_libevent.cc",
+        "message_loop/message_pump_libevent.h",
+        "process/kill_posix.cc",
+        "process/launch.cc",
+        "process/launch.h",
+        "process/launch_posix.cc",
+        "rand_util_posix.cc",
+      ]
+    }
+  } else {
+    # Remove NaCl stuff.
+    sources -= [
+      "memory/shared_memory_nacl.cc",
+      "os_compat_nacl.cc",
+      "os_compat_nacl.h",
+      "rand_util_nacl.cc",
+      "synchronization/read_write_lock_nacl.cc",
+    ]
+  }
+
+  # Windows.
+  if (is_win) {
+    sources += [
+      "profiler/win32_stack_frame_unwinder.cc",
+      "profiler/win32_stack_frame_unwinder.h",
+    ]
+
+    sources -= [
+      "message_loop/message_pump_libevent.cc",
+      "strings/string16.cc",
+    ]
+
+    deps += [
+      "//base/trace_event/etw_manifest:chrome_events_win",
+      "//base/win:base_win_features",
+    ]
+
+    if (is_component_build) {
+      # Copy the VS runtime DLLs into the isolate so that they don't have to be
+      # preinstalled on the target machine. The debug runtimes have a "d" at
+      # the end.
+      if (is_debug) {
+        vcrt_suffix = "d"
+      } else {
+        vcrt_suffix = ""
+      }
+
+      # These runtime files are copied to the output directory by the
+      # vs_toolchain script that runs as part of toolchain configuration.
+      if (visual_studio_version == "2015") {
+        data += [
+          "$root_out_dir/msvcp140${vcrt_suffix}.dll",
+          "$root_out_dir/vccorlib140${vcrt_suffix}.dll",
+          "$root_out_dir/vcruntime140${vcrt_suffix}.dll",
+
+          # Universal Windows 10 CRT files
+          "$root_out_dir/api-ms-win-core-console-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-datetime-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-debug-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-errorhandling-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-file-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-file-l1-2-0.dll",
+          "$root_out_dir/api-ms-win-core-file-l2-1-0.dll",
+          "$root_out_dir/api-ms-win-core-handle-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-heap-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-interlocked-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-libraryloader-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-localization-l1-2-0.dll",
+          "$root_out_dir/api-ms-win-core-memory-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-namedpipe-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-processenvironment-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-processthreads-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-processthreads-l1-1-1.dll",
+          "$root_out_dir/api-ms-win-core-profile-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-rtlsupport-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-string-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-synch-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-synch-l1-2-0.dll",
+          "$root_out_dir/api-ms-win-core-sysinfo-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-timezone-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-core-util-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-conio-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-convert-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-environment-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-filesystem-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-heap-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-locale-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-math-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-multibyte-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-private-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-process-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-runtime-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-stdio-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-string-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-time-l1-1-0.dll",
+          "$root_out_dir/api-ms-win-crt-utility-l1-1-0.dll",
+          "$root_out_dir/ucrtbase${vcrt_suffix}.dll",
+        ]
+      } else {
+        data += [
+          "$root_out_dir/msvcp120${vcrt_suffix}.dll",
+          "$root_out_dir/msvcr120${vcrt_suffix}.dll",
+        ]
+      }
+      if (is_asan) {
+        data += [ "//third_party/llvm-build/Release+Asserts/lib/clang/$clang_version/lib/windows/clang_rt.asan_dynamic-i386.dll" ]
+      }
+    }
+
+    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+    libs = [
+      "cfgmgr32.lib",
+      "powrprof.lib",
+      "setupapi.lib",
+      "userenv.lib",
+      "winmm.lib",
+    ]
+    all_dependent_configs = [ ":base_win_linker_flags" ]
+  } else if (!is_nacl || is_nacl_nonsfi) {
+    # Non-Windows.
+    deps += [ "//base/third_party/libevent" ]
+  }
+
+  # Desktop Mac.
+  if (is_mac) {
+    sources += [
+      "trace_event/malloc_dump_provider.cc",
+      "trace_event/malloc_dump_provider.h",
+    ]
+    libs = [
+      "ApplicationServices.framework",
+      "AppKit.framework",
+      "bsm",
+      "CoreFoundation.framework",
+      "IOKit.framework",
+      "Security.framework",
+    ]
+  }
+
+  # Mac or iOS.
+  if (is_mac || is_ios) {
+    sources -= [
+      "memory/shared_memory_posix.cc",
+      "native_library_posix.cc",
+      "strings/sys_string_conversions_posix.cc",
+      "threading/platform_thread_internal_posix.cc",
+    ]
+  } else {
+    # Non-Mac/ios.
+    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) {
+    sources += [
+      "trace_event/malloc_dump_provider.cc",
+      "trace_event/malloc_dump_provider.h",
+    ]
+
+    if (is_asan || is_lsan || is_msan || is_tsan) {
+      # For llvm-sanitizer.
+      data += [ "//third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6" ]
+    }
+
+    # TODO(brettw) this will need to be parameterized at some point.
+    linux_configs = []
+    if (use_glib) {
+      linux_configs += [ "//build/config/linux:glib" ]
+    }
+
+    defines += [ "USE_SYMBOLIZE" ]
+
+    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/symbolize",
+      "//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",
+      ]
+    }
+  }
+
+  # iOS
+  if (is_ios) {
+    set_sources_assignment_filter([])
+
+    sources -= [
+      "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",
+      "memory/discardable_shared_memory.cc",
+      "memory/discardable_shared_memory.h",
+      "message_loop/message_pump_libevent.cc",
+      "message_loop/message_pump_libevent.h",
+      "process/kill.cc",
+      "process/kill.h",
+      "process/kill_posix.cc",
+      "process/launch.cc",
+      "process/launch.h",
+      "process/launch_posix.cc",
+      "process/memory.cc",
+      "process/memory.h",
+      "process/process_iterator.cc",
+      "process/process_iterator.h",
+      "process/process_metrics_posix.cc",
+      "process/process_posix.cc",
+      "sync_socket.h",
+      "sync_socket_posix.cc",
+    ]
+    sources += [
+      "base_paths_mac.h",
+      "base_paths_mac.mm",
+      "file_version_info_mac.h",
+      "file_version_info_mac.mm",
+      "files/file_util_mac.mm",
+      "mac/bundle_locations.h",
+      "mac/bundle_locations.mm",
+      "mac/call_with_eh_frame.cc",
+      "mac/call_with_eh_frame.h",
+      "mac/foundation_util.h",
+      "mac/foundation_util.mm",
+      "mac/mac_logging.h",
+      "mac/mac_logging.mm",
+      "mac/mach_logging.cc",
+      "mac/mach_logging.h",
+      "mac/objc_property_releaser.h",
+      "mac/objc_property_releaser.mm",
+      "mac/scoped_block.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_nsobject.h",
+      "mac/scoped_nsobject.mm",
+      "mac/scoped_objc_class_swizzler.h",
+      "mac/scoped_objc_class_swizzler.mm",
+      "mac/scoped_typeref.h",
+      "memory/shared_memory_posix.cc",
+      "message_loop/message_pump_mac.h",
+      "message_loop/message_pump_mac.mm",
+      "process/memory_stubs.cc",
+      "strings/sys_string_conversions_mac.mm",
+      "threading/platform_thread_mac.mm",
+      "time/time_mac.cc",
+    ]
+
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  if (!use_glib) {
+    sources -= [
+      "message_loop/message_pump_glib.cc",
+      "message_loop/message_pump_glib.h",
+    ]
+  }
+
+  if (is_asan || is_lsan || is_msan || is_tsan) {
+    data += [ "//tools/valgrind/asan/" ]
+    if (is_win) {
+      data +=
+          [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer.exe" ]
+    } else {
+      data += [ "//third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer" ]
+    }
+  }
+
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+
+  allow_circular_includes_from = public_deps
+}
+
+buildflag_header("debugging_flags") {
+  header = "debugging_flags.h"
+  header_dir = "base/debug"
+  flags = [ "ENABLE_PROFILING=$enable_profiling" ]
+}
+
+# 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.
+static_library("base_static") {
+  sources = [
+    "base_switches.cc",
+    "base_switches.h",
+    "win/pe_image.cc",
+    "win/pe_image.h",
+  ]
+
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+}
+
+component("i18n") {
+  output_name = "base_i18n"
+  sources = [
+    "i18n/base_i18n_export.h",
+    "i18n/base_i18n_switches.cc",
+    "i18n/base_i18n_switches.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/message_formatter.cc",
+    "i18n/message_formatter.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" ]
+  public_deps = [
+    "//third_party/icu",
+  ]
+  deps = [
+    ":base",
+    "//base/third_party/dynamic_annotations",
+  ]
+
+  if (!is_debug) {
+    configs -= [ "//build/config/compiler:default_optimization" ]
+    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_mac) {
+    libs = [ "CoreFoundation.framework" ]
+  }
+}
+
+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/gtest",
+    "//testing/perf",
+  ]
+
+  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",
+      "//build/config/sanitizers:deps",
+      "//build/win:default_exe_manifest",
+      "//third_party/icu:icuuc",
+    ]
+  }
+
+  executable("check_example") {
+    sources = [
+      "check_example.cc",
+    ]
+    deps = [
+      ":base",
+      "//build/config/sanitizers:deps",
+      "//build/win:default_exe_manifest",
+    ]
+  }
+}
+
+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",
+    ]
+    deps = [
+      "//build/config/sanitizers:deps",
+    ]
+  }
+
+  loadable_module("scoped_handle_test_dll") {
+    sources = [
+      "win/scoped_handle_test_dll.cc",
+    ]
+    deps = [
+      ":base",
+      "//base/win:base_win_features",
+    ]
+  }
+
+  if (current_cpu == "x64") {
+    # Must be a shared library so that it can be unloaded during testing.
+    shared_library("base_profiler_test_support_library") {
+      sources = [
+        "profiler/test_support_library.cc",
+      ]
+      deps = [
+        "//build/config/sanitizers:deps",
+      ]
+    }
+  }
+}
+
+bundle_data("base_unittests_bundle_data") {
+  testonly = true
+  sources = [
+    "test/data/file_util/binary_file.bin",
+    "test/data/file_util/binary_file_diff.bin",
+    "test/data/file_util/binary_file_same.bin",
+    "test/data/file_util/blank_line.txt",
+    "test/data/file_util/blank_line_crlf.txt",
+    "test/data/file_util/crlf.txt",
+    "test/data/file_util/different.txt",
+    "test/data/file_util/different_first.txt",
+    "test/data/file_util/different_last.txt",
+    "test/data/file_util/empty1.txt",
+    "test/data/file_util/empty2.txt",
+    "test/data/file_util/first1.txt",
+    "test/data/file_util/first2.txt",
+    "test/data/file_util/original.txt",
+    "test/data/file_util/same.txt",
+    "test/data/file_util/same_length.txt",
+    "test/data/file_util/shortened.txt",
+    "test/data/json/bom_feff.json",
+    "test/data/serializer_nested_test.json",
+    "test/data/serializer_test.json",
+    "test/data/serializer_test_nowhitespace.json",
+  ]
+  outputs = [
+    "{{bundle_resources_dir}}/" +
+        "{{source_root_relative_dir}}/{{source_file_part}}",
+  ]
+}
+
+if (is_ios || is_mac) {
+  source_set("base_unittests_arc") {
+    testonly = true
+    set_sources_assignment_filter([])
+    sources = [
+      "mac/bind_objc_block_unittest_arc.mm",
+      "mac/scoped_nsobject_unittest_arc.mm",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+    configs += [ "//build/config/compiler:enable_arc" ]
+    deps = [
+      ":base",
+      "//testing/gtest",
+    ]
+  }
+}
+
+test("base_unittests") {
+  sources = [
+    "allocator/tcmalloc_unittest.cc",
+    "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",
+    "at_exit_unittest.cc",
+    "atomicops_unittest.cc",
+    "barrier_closure_unittest.cc",
+    "base64_unittest.cc",
+    "base64url_unittest.cc",
+    "big_endian_unittest.cc",
+    "bind_unittest.cc",
+    "bit_cast_unittest.cc",
+    "bits_unittest.cc",
+    "build_time_unittest.cc",
+    "callback_helpers_unittest.cc",
+    "callback_list_unittest.cc",
+    "callback_unittest.cc",
+    "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/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",
+    "feature_list_unittest.cc",
+    "file_version_info_win_unittest.cc",
+    "files/dir_reader_posix_unittest.cc",
+    "files/file_locking_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/message_formatter_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/call_with_eh_frame_unittest.mm",
+    "mac/dispatch_source_mach_unittest.cc",
+    "mac/foundation_util_unittest.mm",
+    "mac/mac_util_unittest.mm",
+    "mac/mach_port_broker_unittest.cc",
+    "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_listener_unittest.cc",
+    "memory/memory_pressure_monitor_chromeos_unittest.cc",
+    "memory/memory_pressure_monitor_mac_unittest.cc",
+    "memory/memory_pressure_monitor_win_unittest.cc",
+    "memory/ptr_util_unittest.cc",
+    "memory/ref_counted_memory_unittest.cc",
+    "memory/ref_counted_unittest.cc",
+    "memory/scoped_vector_unittest.cc",
+    "memory/shared_memory_mac_unittest.cc",
+    "memory/shared_memory_unittest.cc",
+    "memory/shared_memory_win_unittest.cc",
+    "memory/singleton_unittest.cc",
+    "memory/weak_ptr_unittest.cc",
+    "message_loop/message_loop_task_runner_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_macros_unittest.cc",
+    "metrics/histogram_snapshot_manager_unittest.cc",
+    "metrics/histogram_unittest.cc",
+    "metrics/metrics_hashes_unittest.cc",
+    "metrics/persistent_histogram_allocator_unittest.cc",
+    "metrics/persistent_memory_allocator_unittest.cc",
+    "metrics/persistent_sample_map_unittest.cc",
+    "metrics/sample_map_unittest.cc",
+    "metrics/sample_vector_unittest.cc",
+    "metrics/sparse_histogram_unittest.cc",
+    "metrics/statistics_recorder_unittest.cc",
+    "native_library_unittest.cc",
+    "numerics/safe_numerics_unittest.cc",
+    "observer_list_unittest.cc",
+    "optional_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",
+    "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",
+    "run_loop_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/pattern_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/read_write_lock_unittest.cc",
+    "synchronization/waitable_event_unittest.cc",
+    "synchronization/waitable_event_watcher_unittest.cc",
+    "sys_byteorder_unittest.cc",
+    "sys_info_unittest.cc",
+    "system_monitor/system_monitor_unittest.cc",
+    "task/cancelable_task_tracker_unittest.cc",
+    "task_runner_util_unittest.cc",
+    "task_scheduler/delayed_task_manager_unittest.cc",
+    "task_scheduler/priority_queue_unittest.cc",
+    "task_scheduler/scheduler_lock_unittest.cc",
+    "task_scheduler/scheduler_service_thread_unittest.cc",
+    "task_scheduler/scheduler_worker_pool_impl_unittest.cc",
+    "task_scheduler/scheduler_worker_stack_unittest.cc",
+    "task_scheduler/scheduler_worker_unittest.cc",
+    "task_scheduler/sequence_sort_key_unittest.cc",
+    "task_scheduler/sequence_unittest.cc",
+    "task_scheduler/task_scheduler_impl_unittest.cc",
+    "task_scheduler/task_tracker_unittest.cc",
+    "task_scheduler/test_task_factory.cc",
+    "task_scheduler/test_task_factory.h",
+    "task_scheduler/test_utils.h",
+    "template_util_unittest.cc",
+    "test/histogram_tester_unittest.cc",
+    "test/icu_test_util.cc",
+    "test/icu_test_util.h",
+    "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_task_runner_handle_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",
+    "trace_event/blame_context_unittest.cc",
+    "trace_event/heap_profiler_allocation_context_tracker_unittest.cc",
+    "trace_event/heap_profiler_allocation_register_unittest.cc",
+    "trace_event/heap_profiler_heap_dump_writer_unittest.cc",
+    "trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc",
+    "trace_event/heap_profiler_type_name_deduplicator_unittest.cc",
+    "trace_event/java_heap_dump_provider_android_unittest.cc",
+    "trace_event/memory_allocator_dump_unittest.cc",
+    "trace_event/memory_dump_manager_unittest.cc",
+    "trace_event/process_memory_dump_unittest.cc",
+    "trace_event/trace_config_unittest.cc",
+    "trace_event/trace_event_argument_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/winheap_dump_provider_win_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_handle_unittest.cc",
+    "win/scoped_process_information_unittest.cc",
+    "win/scoped_variant_unittest.cc",
+    "win/shortcut_unittest.cc",
+    "win/startup_information_unittest.cc",
+    "win/wait_chain_unittest.cc",
+    "win/win_util_unittest.cc",
+    "win/windows_version_unittest.cc",
+    "win/wrapped_window_proc_unittest.cc",
+  ]
+
+  defines = []
+
+  deps = [
+    ":base",
+    ":i18n",
+    ":message_loop_tests",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//base/third_party/dynamic_annotations",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/icu",
+  ]
+
+  if (is_ios || is_mac) {
+    deps += [ ":base_unittests_arc" ]
+  }
+
+  public_deps = [
+    ":base_unittests_bundle_data",
+  ]
+
+  # Some unittests depend on the ALLOCATOR_SHIM macro.
+  configs += [ "//base/allocator:allocator_shim_define" ]
+
+  data = [
+    "test/data/",
+  ]
+
+  # Allow more direct string conversions on platforms with native utf8
+  # strings
+  if (is_mac || is_ios || is_chromeos || is_chromecast) {
+    defines += [ "SYSTEM_NATIVE_UTF8" ]
+  }
+
+  if (is_android) {
+    deps += [
+      ":base_java",
+      ":base_java_unittest_support",
+      "//base/android/jni_generator:jni_generator_tests",
+    ]
+  }
+
+  if (is_ios) {
+    sources -= [
+      "files/file_locking_unittest.cc",
+      "files/file_path_watcher_unittest.cc",
+      "memory/discardable_shared_memory_unittest.cc",
+      "memory/shared_memory_unittest.cc",
+      "process/memory_unittest.cc",
+      "process/process_unittest.cc",
+      "process/process_util_unittest.cc",
+      "sync_socket_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",
+      "strings/sys_string_conversions_mac_unittest.mm",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    # TODO(GYP): dep on copy_test_data_ios action.
+  }
+
+  if (is_mac) {
+    libs = [
+      "CoreFoundation.framework",
+      "Foundation.framework",
+    ]
+  }
+
+  if (is_linux) {
+    if (is_desktop_linux) {
+      sources += [ "nix/xdg_util_unittest.cc" ]
+    }
+
+    deps += [ "//base/test:malloc_wrapper" ]
+
+    if (use_glib) {
+      configs += [ "//build/config/linux:glib" ]
+    }
+
+    if (!is_component_build) {
+      # Set rpath to find libmalloc_wrapper.so even in a non-component build.
+      configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
+    }
+  }
+
+  if (!use_glib) {
+    sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
+  }
+
+  if (is_posix && !is_ios) {
+    sources += [ "message_loop/message_pump_libevent_unittest.cc" ]
+    deps += [ "//base/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",
+      "trace_event/trace_event_android_unittest.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  if (is_win) {
+    deps += [ "//base:scoped_handle_test_dll" ]
+    if (current_cpu == "x64") {
+      sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ]
+      deps += [ ":base_profiler_test_support_library" ]
+    }
+  }
+
+  if (use_experimental_allocator_shim) {
+    sources += [ "allocator/allocator_shim_unittest.cc" ]
+  }
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  # Symbols for crashes when running tests on swarming.
+  if (symbol_level > 0) {
+    if (is_win) {
+      data += [ "$root_out_dir/base_unittests.exe.pdb" ]
+    } else if (is_mac) {
+      # TODO(crbug.com/330301): make this conditional on mac_strip_release.
+      # data += [ "$root_out_dir/base_unittests.dSYM/" ]
+    }
+  }
+
+  if (use_cfi_cast) {
+    # TODO(krasin): remove CFI_CAST_CHECK, see https://crbug.com/626794.
+    defines += [ "CFI_CAST_CHECK" ]
+  }
+}
+
+action("build_date") {
+  script = "//build/write_build_date_header.py"
+
+  # Force recalculation if there's been a change.
+  inputs = [
+    "//build/util/LASTCHANGE",
+  ]
+  outputs = [
+    "$target_gen_dir/generated_build_date.h",
+  ]
+
+  args =
+      [ rebase_path("$target_gen_dir/generated_build_date.h", root_build_dir) ]
+
+  if (is_official_build) {
+    args += [ "official" ]
+  } else {
+    args += [ "default" ]
+  }
+
+  if (override_build_date != "N/A") {
+    args += [ override_build_date ]
+  }
+}
+
+if (enable_nocompile_tests) {
+  nocompile_test("base_nocompile_tests") {
+    sources = [
+      "bind_unittest.nc",
+      "callback_list_unittest.nc",
+      "callback_unittest.nc",
+      "memory/weak_ptr_unittest.nc",
+    ]
+
+    deps = [
+      ":base",
+      "//base/test:run_all_unittests",
+      "//testing/gtest",
+    ]
+  }
+}
+
+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/Callback.java",
+      "android/java/src/org/chromium/base/CommandLine.java",
+      "android/java/src/org/chromium/base/ContentUriUtils.java",
+      "android/java/src/org/chromium/base/ContextUtils.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",
+    ]
+
+    public_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_build_config_gen",
+      ":base_native_libraries_gen",
+    ]
+
+    deps = [
+      "//third_party/android_tools:android_support_multidex_java",
+      "//third_party/jsr-305:jsr_305_javalib",
+    ]
+
+    java_files = [
+      "android/java/src/org/chromium/base/ActivityState.java",
+      "android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java",
+      "android/java/src/org/chromium/base/ApiCompatibilityUtils.java",
+      "android/java/src/org/chromium/base/ApkAssets.java",
+      "android/java/src/org/chromium/base/ApplicationStatus.java",
+      "android/java/src/org/chromium/base/BaseChromiumApplication.java",
+      "android/java/src/org/chromium/base/BaseSwitches.java",
+      "android/java/src/org/chromium/base/BuildInfo.java",
+      "android/java/src/org/chromium/base/Callback.java",
+      "android/java/src/org/chromium/base/CollectionUtil.java",
+      "android/java/src/org/chromium/base/CommandLine.java",
+      "android/java/src/org/chromium/base/CommandLineInitUtil.java",
+      "android/java/src/org/chromium/base/ContentUriUtils.java",
+      "android/java/src/org/chromium/base/ContextUtils.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/FileUtils.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/Log.java",
+      "android/java/src/org/chromium/base/MemoryPressureListener.java",
+      "android/java/src/org/chromium/base/ObserverList.java",
+      "android/java/src/org/chromium/base/PackageUtils.java",
+      "android/java/src/org/chromium/base/PathService.java",
+      "android/java/src/org/chromium/base/PathUtils.java",
+      "android/java/src/org/chromium/base/PerfTraceEvent.java",
+      "android/java/src/org/chromium/base/PowerMonitor.java",
+      "android/java/src/org/chromium/base/PowerStatusReceiver.java",
+      "android/java/src/org/chromium/base/Promise.java",
+      "android/java/src/org/chromium/base/ResourceExtractor.java",
+      "android/java/src/org/chromium/base/SecureRandomInitializer.java",
+      "android/java/src/org/chromium/base/StreamUtil.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/VisibleForTesting.java",
+      "android/java/src/org/chromium/base/annotations/AccessedByNative.java",
+      "android/java/src/org/chromium/base/annotations/CalledByNative.java",
+      "android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java",
+      "android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java",
+      "android/java/src/org/chromium/base/annotations/JNINamespace.java",
+      "android/java/src/org/chromium/base/annotations/MainDex.java",
+      "android/java/src/org/chromium/base/annotations/NativeCall.java",
+      "android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java",
+      "android/java/src/org/chromium/base/annotations/RemovableInRelease.java",
+      "android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java",
+      "android/java/src/org/chromium/base/annotations/UsedByReflection.java",
+      "android/java/src/org/chromium/base/library_loader/LegacyLinker.java",
+      "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
+      "android/java/src/org/chromium/base/library_loader/Linker.java",
+      "android/java/src/org/chromium/base/library_loader/LoaderErrors.java",
+      "android/java/src/org/chromium/base/library_loader/ModernLinker.java",
+      "android/java/src/org/chromium/base/library_loader/NativeLibraryPreloader.java",
+      "android/java/src/org/chromium/base/library_loader/ProcessInitException.java",
+      "android/java/src/org/chromium/base/metrics/RecordHistogram.java",
+      "android/java/src/org/chromium/base/metrics/RecordUserAction.java",
+      "android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java",
+    ]
+
+    # New versions of BuildConfig.java and NativeLibraries.java
+    # (with the actual correct values) will be created when creating an apk.
+    jar_excluded_patterns = [
+      "*/BuildConfig.class",
+      "*/NativeLibraries.class",
+      "*/NativeLibraries##*.class",
+    ]
+  }
+
+  # GYP: //base.gyp:base_javatests
+  android_library("base_javatests") {
+    deps = [
+      ":base_java",
+      ":base_java_test_support",
+    ]
+    java_files = [
+      "android/javatests/src/org/chromium/base/AdvancedMockContextTest.java",
+      "android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java",
+      "android/javatests/src/org/chromium/base/CommandLineInitUtilTest.java",
+      "android/javatests/src/org/chromium/base/CommandLineTest.java",
+      "android/javatests/src/org/chromium/base/ObserverListTest.java",
+      "android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java",
+    ]
+  }
+
+  # GYP: //base.gyp:base_java_test_support
+  android_library("base_java_test_support") {
+    deps = [
+      ":base_java",
+      "//testing/android/reporter:reporter_java",
+    ]
+    java_files = [
+      "test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java",
+      "test/android/javatests/src/org/chromium/base/test/BaseChromiumInstrumentationTestRunner.java",
+      "test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java",
+      "test/android/javatests/src/org/chromium/base/test/BaseTestResult.java",
+      "test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java",
+      "test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java",
+      "test/android/javatests/src/org/chromium/base/test/util/DisableIf.java",
+      "test/android/javatests/src/org/chromium/base/test/util/DisableIfSkipCheck.java",
+      "test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java",
+      "test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java",
+      "test/android/javatests/src/org/chromium/base/test/util/Feature.java",
+      "test/android/javatests/src/org/chromium/base/test/util/FlakyTest.java",
+      "test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java",
+      "test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java",
+      "test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java",
+      "test/android/javatests/src/org/chromium/base/test/util/Manual.java",
+      "test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java",
+      "test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java",
+      "test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheck.java",
+      "test/android/javatests/src/org/chromium/base/test/util/PerfTest.java",
+      "test/android/javatests/src/org/chromium/base/test/util/Restriction.java",
+      "test/android/javatests/src/org/chromium/base/test/util/RestrictionSkipCheck.java",
+      "test/android/javatests/src/org/chromium/base/test/util/RetryOnFailure.java",
+      "test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java",
+      "test/android/javatests/src/org/chromium/base/test/util/SkipCheck.java",
+      "test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java",
+      "test/android/javatests/src/org/chromium/base/test/util/TestThread.java",
+      "test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java",
+      "test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java",
+      "test/android/javatests/src/org/chromium/base/test/util/parameter/BaseParameter.java",
+      "test/android/javatests/src/org/chromium/base/test/util/parameter/Parameter.java",
+      "test/android/javatests/src/org/chromium/base/test/util/parameter/Parameterizable.java",
+      "test/android/javatests/src/org/chromium/base/test/util/parameter/ParameterizedTest.java",
+      "test/android/javatests/src/org/chromium/base/test/util/parameter/parameters/MethodParameter.java",
+    ]
+  }
+
+  # TODO(jbudorick): Remove this once we roll to robolectric 3.0 and pull
+  # in the multidex shadow library. crbug.com/522043
+  # GYP: //base.gyp:base_junit_test_support
+  java_library("base_junit_test_support") {
+    testonly = true
+    java_files = [ "test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java" ]
+    deps = [
+      "//third_party/android_tools:android_support_multidex_java",
+      "//third_party/robolectric:android-all-4.3_r2-robolectric-0",
+      "//third_party/robolectric:robolectric_java",
+    ]
+    srcjar_deps = [ ":base_build_config_gen" ]
+  }
+
+  # GYP: //base.gyp:base_junit_tests
+  junit_binary("base_junit_tests") {
+    java_files = [
+      "android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java",
+      "android/junit/src/org/chromium/base/LogTest.java",
+      "android/junit/src/org/chromium/base/PromiseTest.java",
+      "test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java",
+      "test/android/junit/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheckTest.java",
+      "test/android/junit/src/org/chromium/base/test/util/RestrictionSkipCheckTest.java",
+      "test/android/junit/src/org/chromium/base/test/util/SkipCheckTest.java",
+    ]
+    deps = [
+      ":base_java",
+      ":base_java_test_support",
+      ":base_junit_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",
+    ]
+  }
+
+  # GYP: //base/base.gyp:base_build_config_gen
+  java_cpp_template("base_build_config_gen") {
+    sources = [
+      "android/java/templates/BuildConfig.template",
+    ]
+    package_name = "org/chromium/base"
+
+    defines = []
+    if (!is_java_debug) {
+      defines += [ "NDEBUG" ]
+    }
+  }
+
+  # 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/libchrome/base/DEPS b/libchrome/base/DEPS
new file mode 100644
index 0000000..c0e95a0
--- /dev/null
+++ b/libchrome/base/DEPS
@@ -0,0 +1,15 @@
+include_rules = [
+  "+jni",
+  "+third_party/ashmem",
+  "+third_party/apple_apsl",
+  "+third_party/lss",
+  "+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/libchrome/base/OWNERS b/libchrome/base/OWNERS
new file mode 100644
index 0000000..b6cfce4
--- /dev/null
+++ b/libchrome/base/OWNERS
@@ -0,0 +1,46 @@
+# About src/base:
+#
+# 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.
+#
+# If the code in question does not need to be used inside base, but will have
+# multiple consumers across the codebase, consider placing it in a new directory
+# under components/ instead.
+
+mark@chromium.org
+thakis@chromium.org
+danakj@chromium.org
+thestig@chromium.org
+dcheng@chromium.org
+
+# For Bind/Callback:
+per-file bind*=tzik@chromium.org
+per-file callback*=tzik@chromium.org
+
+# For Android-specific changes:
+per-file *android*=nyquist@chromium.org
+per-file *android*=rmcilroy@chromium.org
+per-file *android*=torne@chromium.org
+per-file *android*=yfriedman@chromium.org
+
+# For FeatureList API:
+per-file feature_list*=asvitkine@chromium.org
+per-file feature_list*=isherman@chromium.org
+
+# For bot infrastructure:
+per-file *.isolate=maruel@chromium.org
+per-file *.isolate=tandrii@chromium.org
+per-file *.isolate=vadimsh@chromium.org
+
+# For TCMalloc tests:
+per-file security_unittest.cc=jln@chromium.org
diff --git a/libchrome/base/PRESUBMIT.py b/libchrome/base/PRESUBMIT.py
new file mode 100644
index 0000000..7fc8107
--- /dev/null
+++ b/libchrome/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/libchrome/base/allocator/BUILD.gn b/libchrome/base/allocator/BUILD.gn
new file mode 100644
index 0000000..490b8e8
--- /dev/null
+++ b/libchrome/base/allocator/BUILD.gn
@@ -0,0 +1,327 @@
+# 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/buildflag_header.gni")
+import("//build/config/allocator.gni")
+import("//build/config/compiler/compiler.gni")
+
+declare_args() {
+  # 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).
+  enable_debugallocation = is_debug
+}
+
+# Allocator shim is only enabled for Release static builds.
+win_use_allocator_shim = is_win && !is_component_build && !is_debug
+
+# This "allocator" meta-target will forward to the default allocator according
+# to the build settings.
+group("allocator") {
+  public_deps = []
+  deps = []
+
+  if (use_allocator == "tcmalloc") {
+    deps += [ ":tcmalloc" ]
+  }
+
+  if (win_use_allocator_shim) {
+    public_deps += [ ":allocator_shim" ]
+  }
+}
+
+# This config defines ALLOCATOR_SHIM in the same conditions that the allocator
+# shim will be used by the allocator target.
+#
+# TODO(brettw) this is only used in one place and is kind of mess, because it
+# assumes that the library using it will eventually be linked with
+# //base/allocator in the default way. Clean this up and delete this.
+config("allocator_shim_define") {
+  if (win_use_allocator_shim) {
+    defines = [ "ALLOCATOR_SHIM" ]
+  }
+}
+
+config("tcmalloc_flags") {
+  defines = []
+  if (enable_debugallocation) {
+    defines += [
+      # Use debugallocation for Debug builds to catch problems early
+      # and cleanly, http://crbug.com/30715 .
+      "TCMALLOC_FOR_DEBUGALLOCATION",
+    ]
+  }
+  if (use_experimental_allocator_shim) {
+    defines += [ "TCMALLOC_DONT_REPLACE_SYSTEM_ALLOC" ]
+  }
+  if (is_clang) {
+    cflags = [
+      # tcmalloc initializes some fields in the wrong order.
+      "-Wno-reorder",
+
+      # tcmalloc contains some unused local template specializations.
+      "-Wno-unused-function",
+
+      # tcmalloc uses COMPILE_ASSERT without static_assert but with
+      # typedefs.
+      "-Wno-unused-local-typedefs",
+
+      # for magic2_ in debugallocation.cc (only built in Debug builds)
+      # typedefs.
+      "-Wno-unused-private-field",
+    ]
+  } else {
+    cflags = []
+  }
+
+  if (is_linux || is_android) {
+    # 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",
+    ]
+  }
+}
+
+# This config is only used on Windows static release builds for the
+# allocator shim.
+if (win_use_allocator_shim) {
+  source_set("allocator_shim") {
+    sources = [
+      "allocator_shim_win.cc",
+      "allocator_shim_win.h",
+    ]
+    configs += [ ":allocator_shim_define" ]
+  }
+}
+
+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",
+      "$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/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/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/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/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/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",
+      "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",
+      ":tcmalloc_flags",
+    ]
+
+    deps = []
+
+    if (enable_profiling) {
+      sources += [
+        "$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 += [ "ENABLE_PROFILING=1" ]
+    }
+
+    if (is_linux || is_android) {
+      sources -= [
+        "$tcmalloc_dir/src/system-alloc.h",
+        "$tcmalloc_dir/src/windows/port.cc",
+        "$tcmalloc_dir/src/windows/port.h",
+      ]
+
+      # Compiling tcmalloc with -fvisibility=default is only necessary when
+      # not using the allocator shim, which provides the correct visibility
+      # annotations for those symbols which need to be exported (see
+      # //base/allocator/allocator_shim_override_glibc_weak_symbols.h and
+      # //base/allocator/allocator_shim_internals.h for the definition of
+      # SHIM_ALWAYS_EXPORT).
+      if (!use_experimental_allocator_shim) {
+        configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
+        configs += [ "//build/config/gcc:symbol_visibility_default" ]
+      }
+
+      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:default_optimization" ]
+      configs += [ "//build/config/compiler:optimize_max" ]
+    }
+
+    deps += [ "//base/third_party/dynamic_annotations" ]
+  }
+}  # use_allocator == "tcmalloc"
+
+buildflag_header("features") {
+  header = "features.h"
+  flags = [ "USE_EXPERIMENTAL_ALLOCATOR_SHIM=$use_experimental_allocator_shim" ]
+}
+
+if (use_experimental_allocator_shim) {
+  # Used to shim malloc symbols on Android. see //base/allocator/README.md.
+  config("wrap_malloc_symbols") {
+    ldflags = [
+      "-Wl,-wrap,calloc",
+      "-Wl,-wrap,free",
+      "-Wl,-wrap,malloc",
+      "-Wl,-wrap,memalign",
+      "-Wl,-wrap,posix_memalign",
+      "-Wl,-wrap,pvalloc",
+      "-Wl,-wrap,realloc",
+      "-Wl,-wrap,valloc",
+    ]
+  }
+
+  source_set("unified_allocator_shim") {
+    # TODO(primiano): support other platforms, currently this works only on
+    # Linux/CrOS/Android. http://crbug.com/550886 .
+    configs += [ "//base:base_implementation" ]  # for BASE_EXPORT
+    visibility = [ "//base:base" ]
+    sources = [
+      "allocator_shim.cc",
+      "allocator_shim.h",
+      "allocator_shim_internals.h",
+      "allocator_shim_override_cpp_symbols.h",
+      "allocator_shim_override_libc_symbols.h",
+    ]
+    if (is_linux && use_allocator == "tcmalloc") {
+      sources += [
+        "allocator_shim_default_dispatch_to_tcmalloc.cc",
+        "allocator_shim_override_glibc_weak_symbols.h",
+      ]
+      deps = [
+        ":tcmalloc",
+      ]
+    } else if (is_linux && use_allocator == "none") {
+      sources += [ "allocator_shim_default_dispatch_to_glibc.cc" ]
+    } else if (is_android && use_allocator == "none") {
+      sources += [
+        "allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc",
+        "allocator_shim_override_linker_wrapped_symbols.h",
+      ]
+      all_dependent_configs = [ ":wrap_malloc_symbols" ]
+    }
+  }
+}
diff --git a/libchrome/base/allocator/OWNERS b/libchrome/base/allocator/OWNERS
new file mode 100644
index 0000000..f26394a
--- /dev/null
+++ b/libchrome/base/allocator/OWNERS
@@ -0,0 +1,5 @@
+primiano@chromium.org
+wfh@chromium.org
+
+# For changes to tcmalloc it is advisable to ask jar@chromium.org
+# before proceeding.
diff --git a/libchrome/base/allocator/README.md b/libchrome/base/allocator/README.md
new file mode 100644
index 0000000..164df51
--- /dev/null
+++ b/libchrome/base/allocator/README.md
@@ -0,0 +1,196 @@
+This document describes how malloc / new calls are routed in the various Chrome
+platforms.
+
+Bare in mind that the chromium codebase does not always just use `malloc()`.
+Some examples:
+ - Large parts of the renderer (Blink) use two home-brewed allocators,
+   PartitionAlloc and BlinkGC (Oilpan).
+ - Some subsystems, such as the V8 JavaScript engine, handle memory management
+   autonomously.
+ - Various parts of the codebase use abstractions such as `SharedMemory` or
+   `DiscardableMemory` which, similarly to the above, have their own page-level
+   memory management.
+
+Background
+----------
+The `allocator` target defines at compile-time the platform-specific choice of
+the allocator and extra-hooks which services calls to malloc/new. The relevant
+build-time flags involved are `use_allocator` and `win_use_allocator_shim`.
+
+The default choices are as follows:
+
+**Windows**  
+`use_allocator: winheap`, the default Windows heap.
+Additionally, `static_library` (i.e. non-component) builds have a shim
+layer wrapping malloc/new, which is controlled by `win_use_allocator_shim`.  
+The shim layer provides extra security features, such as preventing large
+allocations that can hit signed vs. unsigned bugs in third_party code.
+
+**Linux Desktop / CrOS**  
+`use_allocator: tcmalloc`, a forked copy of tcmalloc which resides in
+`third_party/tcmalloc/chromium`. Setting `use_allocator: none` causes the build
+to fall back to the system (Glibc) symbols.
+
+**Android**  
+`use_allocator: none`, always use the allocator symbols coming from Android's
+libc (Bionic). As it is developed as part of the OS, it is considered to be
+optimized for small devices and more memory-efficient than other choices.  
+The actual implementation backing malloc symbols in Bionic is up to the board
+config and can vary (typically *dlmalloc* or *jemalloc* on most Nexus devices).
+
+**Mac/iOS**  
+`use_allocator: none`, we always use the system's allocator implementation.
+
+In addition, when building for `asan` / `msan` / `syzyasan` `valgrind`, the
+both the allocator and the shim layer are disabled.
+
+Layering and build deps
+-----------------------
+The `allocator` target provides both the source files for tcmalloc (where
+applicable) and the linker flags required for the Windows shim layer.
+The `base` target is (almost) the only one depending on `allocator`. No other
+targets should depend on it, with the exception of the very few executables /
+dynamic libraries that don't depend, either directly or indirectly, on `base`
+within the scope of a linker unit.
+
+More importantly, **no other place outside of `/base` should depend on the
+specific allocator** (e.g., directly include `third_party/tcmalloc`).
+If such a functional dependency is required that should be achieved using
+abstractions in `base` (see `/base/allocator/allocator_extension.h` and
+`/base/memory/`)
+
+**Why `base` depends on `allocator`?**  
+Because it needs to provide services that depend on the actual allocator
+implementation. In the past `base` used to pretend to be allocator-agnostic
+and get the dependencies injected by other layers. This ended up being an
+inconsistent mess.
+See the [allocator cleanup doc][url-allocator-cleanup] for more context.
+
+Linker unit targets (executables and shared libraries) that depend in some way
+on `base` (most of the targets in the codebase) get automatically the correct
+set of linker flags to pull in tcmalloc or the Windows shim-layer.
+
+
+Source code
+-----------
+This directory contains just the allocator (i.e. shim) layer that switches
+between the different underlying memory allocation implementations.
+
+The tcmalloc library originates outside of Chromium and exists in
+`../../third_party/tcmalloc` (currently, the actual location is 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.
+
+
+Unified allocator shim
+----------------------
+On most platform, Chrome overrides the malloc / operator new symbols (and
+corresponding free / delete and other variants). This is to enforce security
+checks and lately to enable the
+[memory-infra heap profiler][url-memory-infra-heap-profiler].  
+Historically each platform had its special logic for defining the allocator
+symbols in different places of the codebase. The unified allocator shim is
+a project aimed to unify the symbol definition and allocator routing logic in
+a central place.
+
+ - Full documentation: [Allocator shim design doc][url-allocator-shim].
+ - Current state: Available and enabled by default on Linux, CrOS and Android.
+ - Tracking bug: [https://crbug.com/550886][crbug.com/550886].
+ - Build-time flag: `use_experimental_allocator_shim`.
+
+**Overview of the unified allocator shim**  
+The allocator shim consists of three stages:
+```
++-------------------------+    +-----------------------+    +----------------+
+|     malloc & friends    | -> |       shim layer      | -> |   Routing to   |
+|    symbols definition   |    |     implementation    |    |    allocator   |
++-------------------------+    +-----------------------+    +----------------+
+| - libc symbols (malloc, |    | - Security checks     |    | - tcmalloc     |
+|   calloc, free, ...)    |    | - Chain of dispatchers|    | - glibc        |
+| - C++ symbols (operator |    |   that can intercept  |    | - Android      |
+|   new, delete, ...)     |    |   and override        |    |   bionic       |
+| - glibc weak symbols    |    |   allocations         |    | - WinHeap      |
+|   (__libc_malloc, ...)  |    +-----------------------+    +----------------+
++-------------------------+
+```
+
+**1. malloc symbols definition**  
+This stage takes care of overriding the symbols `malloc`, `free`,
+`operator new`, `operator delete` and friends and routing those calls inside the
+allocator shim (next point).
+This is taken care of by the headers in `allocator_shim_override_*`.
+
+*On Linux/CrOS*: the allocator symbols are defined as exported global symbols
+in `allocator_shim_override_libc_symbols.h` (for `malloc`, `free` and friends)
+and in `allocator_shim_override_cpp_symbols.h` (for `operator new`,
+`operator delete` and friends).
+This enables proper interposition of malloc symbols referenced by the main
+executable and any third party libraries. Symbol resolution on Linux is a breadth first search that starts from the root link unit, that is the executable
+(see EXECUTABLE AND LINKABLE FORMAT (ELF) - Portable Formats Specification).
+Additionally, when tcmalloc is the default allocator, some extra glibc symbols
+are also defined in `allocator_shim_override_glibc_weak_symbols.h`, for subtle
+reasons explained in that file.
+The Linux/CrOS shim was introduced by
+[crrev.com/1675143004](https://crrev.com/1675143004).
+
+*On Android*: load-time symbol interposition (unlike the Linux/CrOS case) is not
+possible. This is because Android processes are `fork()`-ed from the Android
+zygote, which pre-loads libc.so and only later native code gets loaded via
+`dlopen()` (symbols from `dlopen()`-ed libraries get a different resolution
+scope).
+In this case, the approach instead of wrapping symbol resolution at link time
+(i.e. during the build), via the `--Wl,-wrap,malloc` linker flag.
+The use of this wrapping flag causes:
+ - All references to allocator symbols in the Chrome codebase to be rewritten as
+   references to `__wrap_malloc` and friends. The `__wrap_malloc` symbols are
+   defined in the `allocator_shim_override_linker_wrapped_symbols.h` and
+   route allocator calls inside the shim layer.
+ - The reference to the original `malloc` symbols (which typically is defined by
+   the system's libc.so) are accessible via the special `__real_malloc` and
+   friends symbols (which will be relocated, at load time, against `malloc`).
+
+In summary, this approach is transparent to the dynamic loader, which still sees
+undefined symbol references to malloc symbols.
+These symbols will be resolved against libc.so as usual.
+More details in [crrev.com/1719433002](https://crrev.com/1719433002).
+
+**2. Shim layer implementation**  
+This stage contains the actual shim implementation. This consists of:
+- A singly linked list of dispatchers (structs with function pointers to `malloc`-like functions). Dispatchers can be dynamically inserted at runtime
+(using the `InsertAllocatorDispatch` API). They can intercept and override
+allocator calls.
+- The security checks (suicide on malloc-failure via `std::new_handler`, etc).
+This happens inside `allocator_shim.cc`
+
+**3. Final allocator routing**  
+The final element of the aforementioned dispatcher chain is statically defined
+at build time and ultimately routes the allocator calls to the actual allocator
+(as described in the *Background* section above). This is taken care of by the
+headers in `allocator_shim_default_dispatch_to_*` files.
+
+
+Appendixes
+----------
+**How does the Windows shim layer replace the malloc symbols?**  
+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 overridden.  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.
+See the script `preb_libc.py` in this folder.
+
+Related links
+-------------
+- [Unified allocator shim doc - Feb 2016][url-allocator-shim]
+- [Allocator cleanup doc - Jan 2016][url-allocator-cleanup]
+- [Proposal to use PartitionAlloc as default allocator](https://crbug.com/339604)
+- [Memory-Infra: Tools to profile memory usage in Chrome](components/tracing/docs/memory_infra.md)
+
+[url-allocator-cleanup]: https://docs.google.com/document/d/1V77Kgp_4tfaaWPEZVxNevoD02wXiatnAv7Ssgr0hmjg/edit?usp=sharing
+[url-memory-infra-heap-profiler]: components/tracing/docs/heap_profiler.md
+[url-allocator-shim]: https://docs.google.com/document/d/1yKlO1AO4XjpDad9rjcBOI15EKdAGsuGO_IeZy0g0kxo/edit?usp=sharing
diff --git a/libchrome/base/allocator/allocator.gyp b/libchrome/base/allocator/allocator.gyp
new file mode 100644
index 0000000..674d4d6
--- /dev/null
+++ b/libchrome/base/allocator/allocator.gyp
@@ -0,0 +1,450 @@
+# Copyright (c) 2012 The Chromium 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,
+    # 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,
+  },
+  'targets': [
+    # The only targets that should depend on allocator are 'base' and
+    # executables that don't depend, directly or indirectly, on base (a few).
+    # All the other targets get a transitive dependency on this target via base.
+    {
+      'target_name': 'allocator',
+      'variables': {
+        'conditions': [
+          ['use_allocator!="none" or (OS=="win" and win_use_allocator_shim==1)', {
+            'allocator_target_type%': 'static_library',
+          }, {
+            'allocator_target_type%': 'none',
+          }],
+        ],
+      },
+      'type': '<(allocator_target_type)',
+      'toolsets': ['host', 'target'],
+      'conditions': [
+        ['OS=="win" and win_use_allocator_shim==1', {
+          'msvs_settings': {
+            # TODO(sgk):  merge this with build/common.gypi settings
+            'VCLibrarianTool': {
+              'AdditionalOptions': ['/ignore:4006,4221'],
+            },
+            'VCLinkerTool': {
+              'AdditionalOptions': ['/ignore:4006'],
+            },
+          },
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'allocator_shim_win.cc',
+            'allocator_shim_win.h',
+          ],
+          'configurations': {
+            'Debug_Base': {
+              'msvs_settings': {
+                'VCCLCompilerTool': {
+                  'RuntimeLibrary': '0',
+                },
+              },
+            },
+          },
+        }],  # OS=="win"
+        ['use_allocator=="tcmalloc"', {
+          # Disable the heap checker in tcmalloc.
+          'defines': [
+            'NO_HEAP_CHECK',
+          ],
+          'dependencies': [
+            '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+          ],
+          # The order of this include_dirs matters, as tc-malloc has its own
+          # base/ mini-fork. Do not factor these out of this conditions section.
+          '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/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/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/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',
+          ],
+          'variables': {
+            'clang_warning_flags': [
+              # tcmalloc initializes some fields in the wrong order.
+              '-Wno-reorder',
+              # tcmalloc contains some unused local template specializations.
+              '-Wno-unused-function',
+              # tcmalloc uses COMPILE_ASSERT without static_assert but with
+              # typedefs.
+              '-Wno-unused-local-typedefs',
+              # for magic2_ in debugallocation.cc (only built in Debug builds)
+              # typedefs.
+              '-Wno-unused-private-field',
+            ],
+          },
+          'conditions': [
+            ['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',
+              ],
+              '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',
+                ],
+              },
+              # Compiling tcmalloc with -fvisibility=default is only necessary when
+              # not using the allocator shim, which provides the correct visibility
+              # annotations for those symbols which need to be exported (see
+              # //base/allocator/allocator_shim_override_glibc_weak_symbols.h and
+              # //base/allocator/allocator_shim_internals.h for the definition of
+              # SHIM_ALWAYS_EXPORT).
+              'conditions': [
+                ['use_experimental_allocator_shim==0', {
+                  'cflags!': [
+                    '-fvisibility=hidden',
+                  ],
+                }],
+              ],
+            }],
+            ['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',
+              ],
+            }],
+            ['use_experimental_allocator_shim==1', {
+              'defines': [
+                'TCMALLOC_DONT_REPLACE_SYSTEM_ALLOC',
+              ],
+            }]
+          ],
+          'configurations': {
+            'Debug_Base': {
+              'conditions': [
+                ['disable_debugallocation==0', {
+                  'defines': [
+                    # Use debugallocation for Debug builds to catch problems
+                    # early and cleanly, http://crbug.com/30715 .
+                    'TCMALLOC_FOR_DEBUGALLOCATION',
+                  ],
+                }],
+              ],
+            },
+          },
+        }],  # use_allocator=="tcmalloc
+        # For CrOS builds with vtable verification. According to the author of
+        # crrev.com/10854031 this is used in conjuction with some other CrOS
+        # build flag, to enable verification of any allocator that uses virtual
+        # function calls.
+        ['use_vtable_verify==1', {
+          'cflags': [
+            '-fvtable-verify=preinit',
+          ],
+        }],
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset=="target"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+      ],  # conditions of 'allocator' target.
+    },  # 'allocator' target.
+    {
+      # GN: //base/allocator:features
+      # When referenced from a target that might be compiled in the host
+      # toolchain, always refer to 'allocator_features#target'.
+      'target_name': 'allocator_features',
+      'includes': [ '../../build/buildflag_header.gypi' ],
+      'variables': {
+        'buildflag_header_path': 'base/allocator/features.h',
+        'buildflag_flags': [
+          'USE_EXPERIMENTAL_ALLOCATOR_SHIM=<(use_experimental_allocator_shim)',
+        ],
+      },
+    },  # 'allocator_features' target.
+  ],  # targets.
+  'conditions': [
+    ['use_experimental_allocator_shim==1', {
+      'targets': [
+        {
+          # GN: //base/allocator:unified_allocator_shim
+          'target_name': 'unified_allocator_shim',
+          'toolsets': ['host', 'target'],
+          'type': 'static_library',
+          'defines': [ 'BASE_IMPLEMENTATION' ],
+          'sources': [
+            'allocator_shim.cc',
+            'allocator_shim.h',
+            'allocator_shim_internals.h',
+            'allocator_shim_override_cpp_symbols.h',
+            'allocator_shim_override_libc_symbols.h',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'conditions': [
+            ['OS=="linux" and use_allocator=="tcmalloc"', {
+              'sources': [
+                'allocator_shim_default_dispatch_to_tcmalloc.cc',
+                'allocator_shim_override_glibc_weak_symbols.h',
+              ],
+            }],
+            ['use_allocator=="none" and (OS=="linux" or (OS=="android" and _toolset == "host" and host_os == "linux"))', {
+              'sources': [
+                'allocator_shim_default_dispatch_to_glibc.cc',
+              ],
+            }],
+            ['OS=="android" and _toolset == "target"', {
+              'sources': [
+                'allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc',
+                'allocator_shim_override_linker_wrapped_symbols.h',
+              ],
+              # On Android all references to malloc & friends symbols are
+              # rewritten, at link time, and routed to the shim.
+              # See //base/allocator/README.md.
+              'all_dependent_settings': {
+                'ldflags': [
+                  '-Wl,-wrap,calloc',
+                  '-Wl,-wrap,free',
+                  '-Wl,-wrap,malloc',
+                  '-Wl,-wrap,memalign',
+                  '-Wl,-wrap,posix_memalign',
+                  '-Wl,-wrap,pvalloc',
+                  '-Wl,-wrap,realloc',
+                  '-Wl,-wrap,valloc',
+                ],
+              },
+            }],
+          ]
+        },  # 'unified_allocator_shim' target.
+      ],
+    }]
+  ],
+}
diff --git a/libchrome/base/allocator/allocator_extension.cc b/libchrome/base/allocator/allocator_extension.cc
new file mode 100644
index 0000000..9a3d114
--- /dev/null
+++ b/libchrome/base/allocator/allocator_extension.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.
+
+#include "base/allocator/allocator_extension.h"
+
+#include "base/logging.h"
+
+#if defined(USE_TCMALLOC)
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/malloc_extension.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/malloc_hook.h"
+#endif
+
+namespace base {
+namespace allocator {
+
+void ReleaseFreeMemory() {
+#if defined(USE_TCMALLOC)
+  ::MallocExtension::instance()->ReleaseFreeMemory();
+#endif
+}
+
+bool GetNumericProperty(const char* name, size_t* value) {
+#if defined(USE_TCMALLOC)
+  return ::MallocExtension::instance()->GetNumericProperty(name, value);
+#endif
+  return false;
+}
+
+bool IsHeapProfilerRunning() {
+#if defined(USE_TCMALLOC)
+  return ::IsHeapProfilerRunning();
+#endif
+  return false;
+}
+
+void SetHooks(AllocHookFunc alloc_hook, FreeHookFunc free_hook) {
+// TODO(sque): Use allocator shim layer instead.
+#if defined(USE_TCMALLOC)
+  // Make sure no hooks get overwritten.
+  auto prev_alloc_hook = MallocHook::SetNewHook(alloc_hook);
+  if (alloc_hook)
+    DCHECK(!prev_alloc_hook);
+
+  auto prev_free_hook = MallocHook::SetDeleteHook(free_hook);
+  if (free_hook)
+    DCHECK(!prev_free_hook);
+#endif
+}
+
+int GetCallStack(void** stack, int max_stack_size) {
+#if defined(USE_TCMALLOC)
+  return MallocHook::GetCallerStackTrace(stack, max_stack_size, 0);
+#endif
+  return 0;
+}
+
+}  // namespace allocator
+}  // namespace base
diff --git a/libchrome/base/allocator/allocator_extension.h b/libchrome/base/allocator/allocator_extension.h
new file mode 100644
index 0000000..9f2775a
--- /dev/null
+++ b/libchrome/base/allocator/allocator_extension.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_ALLOCATOR_ALLOCATOR_EXTENSION_H_
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
+
+#include <stddef.h> // for size_t
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace allocator {
+
+// Callback types for alloc and free.
+using AllocHookFunc = void (*)(const void*, size_t);
+using FreeHookFunc = void (*)(const void*);
+
+// Request that the allocator release any free memory it knows about to the
+// system.
+BASE_EXPORT void ReleaseFreeMemory();
+
+// Get the named property's |value|. Returns true if the property is known.
+// Returns false if the property is not a valid property name for the current
+// allocator implementation.
+// |name| or |value| cannot be NULL
+BASE_EXPORT bool GetNumericProperty(const char* name, size_t* value);
+
+BASE_EXPORT bool IsHeapProfilerRunning();
+
+// Register callbacks for alloc and free. Can only store one callback at a time
+// for each of alloc and free.
+BASE_EXPORT void SetHooks(AllocHookFunc alloc_hook, FreeHookFunc free_hook);
+
+// Attempts to unwind the call stack from the current location where this
+// function is being called from. Must be called from a hook function registered
+// by calling SetSingle{Alloc,Free}Hook, directly or indirectly.
+//
+// Arguments:
+//   stack:          pointer to a pre-allocated array of void*'s.
+//   max_stack_size: indicates the size of the array in |stack|.
+//
+// Returns the number of call stack frames stored in |stack|, or 0 if no call
+// stack information is available.
+BASE_EXPORT int GetCallStack(void** stack, int max_stack_size);
+
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
diff --git a/libchrome/base/allocator/allocator_shim.cc b/libchrome/base/allocator/allocator_shim.cc
new file mode 100644
index 0000000..09ed45f
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim.cc
@@ -0,0 +1,260 @@
+// Copyright 2016 The Chromium Authors. All 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_shim.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <new>
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+
+// No calls to malloc / new in this file. They would would cause re-entrancy of
+// the shim, which is hard to deal with. Keep this code as simple as possible
+// and don't use any external C++ object here, not even //base ones. Even if
+// they are safe to use today, in future they might be refactored.
+
+namespace {
+
+using namespace base;
+
+subtle::AtomicWord g_chain_head = reinterpret_cast<subtle::AtomicWord>(
+    &allocator::AllocatorDispatch::default_dispatch);
+
+bool g_call_new_handler_on_malloc_failure = false;
+subtle::Atomic32 g_new_handler_lock = 0;
+
+// In theory this should be just base::ThreadChecker. But we can't afford
+// the luxury of a LazyInstance<ThreadChecker> here as it would cause a new().
+bool CalledOnValidThread() {
+  using subtle::Atomic32;
+  const Atomic32 kInvalidTID = static_cast<Atomic32>(kInvalidThreadId);
+  static Atomic32 g_tid = kInvalidTID;
+  Atomic32 cur_tid = static_cast<Atomic32>(PlatformThread::CurrentId());
+  Atomic32 prev_tid =
+      subtle::NoBarrier_CompareAndSwap(&g_tid, kInvalidTID, cur_tid);
+  return prev_tid == kInvalidTID || prev_tid == cur_tid;
+}
+
+inline size_t GetPageSize() {
+  static size_t pagesize = 0;
+  if (!pagesize)
+    pagesize = sysconf(_SC_PAGESIZE);
+  return pagesize;
+}
+
+// Calls the std::new handler thread-safely. Returns true if a new_handler was
+// set and called, false if no new_handler was set.
+bool CallNewHandler() {
+  // TODO(primiano): C++11 has introduced ::get_new_handler() which is supposed
+  // to be thread safe and would avoid the spinlock boilerplate here. However
+  // it doesn't seem to be available yet in the Linux chroot headers yet.
+  std::new_handler nh;
+  {
+    while (subtle::Acquire_CompareAndSwap(&g_new_handler_lock, 0, 1))
+      PlatformThread::YieldCurrentThread();
+    nh = std::set_new_handler(0);
+    ignore_result(std::set_new_handler(nh));
+    subtle::Release_Store(&g_new_handler_lock, 0);
+  }
+  if (!nh)
+    return false;
+  (*nh)();
+  // Assume the new_handler will abort if it fails. Exception are disabled and
+  // we don't support the case of a new_handler throwing std::bad_balloc.
+  return true;
+}
+
+inline const allocator::AllocatorDispatch* GetChainHead() {
+  // TODO(primiano): Just use NoBarrier_Load once crbug.com/593344 is fixed.
+  // Unfortunately due to that bug NoBarrier_Load() is mistakenly fully
+  // barriered on Linux+Clang, and that causes visible perf regressons.
+  return reinterpret_cast<const allocator::AllocatorDispatch*>(
+#if defined(OS_LINUX) && defined(__clang__)
+      *static_cast<const volatile subtle::AtomicWord*>(&g_chain_head)
+#else
+      subtle::NoBarrier_Load(&g_chain_head)
+#endif
+  );
+}
+
+}  // namespace
+
+namespace base {
+namespace allocator {
+
+void SetCallNewHandlerOnMallocFailure(bool value) {
+  g_call_new_handler_on_malloc_failure = value;
+}
+
+void* UncheckedAlloc(size_t size) {
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  return chain_head->alloc_function(chain_head, size);
+}
+
+void InsertAllocatorDispatch(AllocatorDispatch* dispatch) {
+  // Ensure this is always called on the same thread.
+  DCHECK(CalledOnValidThread());
+
+  dispatch->next = GetChainHead();
+
+  // This function does not guarantee to be thread-safe w.r.t. concurrent
+  // insertions, but still has to guarantee that all the threads always
+  // see a consistent chain, hence the MemoryBarrier() below.
+  // InsertAllocatorDispatch() is NOT a fastpath, as opposite to malloc(), so
+  // we don't really want this to be a release-store with a corresponding
+  // acquire-load during malloc().
+  subtle::MemoryBarrier();
+
+  subtle::NoBarrier_Store(&g_chain_head,
+                          reinterpret_cast<subtle::AtomicWord>(dispatch));
+}
+
+void RemoveAllocatorDispatchForTesting(AllocatorDispatch* dispatch) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(GetChainHead(), dispatch);
+  subtle::NoBarrier_Store(&g_chain_head,
+                          reinterpret_cast<subtle::AtomicWord>(dispatch->next));
+}
+
+}  // namespace allocator
+}  // namespace base
+
+// The Shim* functions below are the entry-points into the shim-layer and
+// are supposed to be invoked / aliased by the allocator_shim_override_*
+// headers to route the malloc / new symbols through the shim layer.
+extern "C" {
+
+// The general pattern for allocations is:
+// - Try to allocate, if succeded return the pointer.
+// - If the allocation failed:
+//   - Call the std::new_handler if it was a C++ allocation.
+//   - Call the std::new_handler if it was a malloc() (or calloc() or similar)
+//     AND SetCallNewHandlerOnMallocFailure(true).
+//   - If the std::new_handler is NOT set just return nullptr.
+//   - If the std::new_handler is set:
+//     - Assume it will abort() if it fails (very likely the new_handler will
+//       just suicide priting a message).
+//     - Assume it did succeed if it returns, in which case reattempt the alloc.
+
+void* ShimCppNew(size_t size) {
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  void* ptr;
+  do {
+    ptr = chain_head->alloc_function(chain_head, size);
+  } while (!ptr && CallNewHandler());
+  return ptr;
+}
+
+void ShimCppDelete(void* address) {
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  return chain_head->free_function(chain_head, address);
+}
+
+void* ShimMalloc(size_t size) {
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  void* ptr;
+  do {
+    ptr = chain_head->alloc_function(chain_head, size);
+  } while (!ptr && g_call_new_handler_on_malloc_failure && CallNewHandler());
+  return ptr;
+}
+
+void* ShimCalloc(size_t n, size_t size) {
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  void* ptr;
+  do {
+    ptr = chain_head->alloc_zero_initialized_function(chain_head, n, size);
+  } while (!ptr && g_call_new_handler_on_malloc_failure && CallNewHandler());
+  return ptr;
+}
+
+void* ShimRealloc(void* address, size_t size) {
+  // realloc(size == 0) means free() and might return a nullptr. We should
+  // not call the std::new_handler in that case, though.
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  void* ptr;
+  do {
+    ptr = chain_head->realloc_function(chain_head, address, size);
+  } while (!ptr && size && g_call_new_handler_on_malloc_failure &&
+           CallNewHandler());
+  return ptr;
+}
+
+void* ShimMemalign(size_t alignment, size_t size) {
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  void* ptr;
+  do {
+    ptr = chain_head->alloc_aligned_function(chain_head, alignment, size);
+  } while (!ptr && g_call_new_handler_on_malloc_failure && CallNewHandler());
+  return ptr;
+}
+
+int ShimPosixMemalign(void** res, size_t alignment, size_t size) {
+  // posix_memalign is supposed to check the arguments. See tc_posix_memalign()
+  // in tc_malloc.cc.
+  if (((alignment % sizeof(void*)) != 0) ||
+      ((alignment & (alignment - 1)) != 0) || (alignment == 0)) {
+    return EINVAL;
+  }
+  void* ptr = ShimMemalign(alignment, size);
+  *res = ptr;
+  return ptr ? 0 : ENOMEM;
+}
+
+void* ShimValloc(size_t size) {
+  return ShimMemalign(GetPageSize(), size);
+}
+
+void* ShimPvalloc(size_t size) {
+  // pvalloc(0) should allocate one page, according to its man page.
+  if (size == 0) {
+    size = GetPageSize();
+  } else {
+    size = (size + GetPageSize() - 1) & ~(GetPageSize() - 1);
+  }
+  return ShimMemalign(GetPageSize(), size);
+}
+
+void ShimFree(void* address) {
+  const allocator::AllocatorDispatch* const chain_head = GetChainHead();
+  return chain_head->free_function(chain_head, address);
+}
+
+}  // extern "C"
+
+// Cpp symbols (new / delete) should always be routed through the shim layer.
+#include "base/allocator/allocator_shim_override_cpp_symbols.h"
+
+// Android does not support symbol interposition. The way malloc symbols are
+// intercepted on Android is by using link-time -wrap flags.
+#if !defined(OS_ANDROID) && !defined(ANDROID)
+// Ditto for plain malloc() / calloc() / free() etc. symbols.
+#include "base/allocator/allocator_shim_override_libc_symbols.h"
+#else
+#include "base/allocator/allocator_shim_override_linker_wrapped_symbols.h"
+#endif
+
+// In the case of tcmalloc we also want to plumb into the glibc hooks
+// to avoid that allocations made in glibc itself (e.g., strdup()) get
+// accidentally performed on the glibc heap instead of the tcmalloc one.
+#if defined(USE_TCMALLOC)
+#include "base/allocator/allocator_shim_override_glibc_weak_symbols.h"
+#endif
+
+// Cross-checks.
+
+#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+#error The allocator shim should not be compiled when building for memory tools.
+#endif
+
+#if (defined(__GNUC__) && defined(__EXCEPTIONS)) || \
+    (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS)
+#error This code cannot be used when exceptions are turned on.
+#endif
diff --git a/libchrome/base/allocator/allocator_shim.h b/libchrome/base/allocator/allocator_shim.h
new file mode 100644
index 0000000..f1a1e3d
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim.h
@@ -0,0 +1,96 @@
+// Copyright 2016 The Chromium Authors. All 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_SHIM_H_
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace allocator {
+
+// Allocator Shim API. Allows to to:
+//  - Configure the behavior of the allocator (what to do on OOM failures).
+//  - Install new hooks (AllocatorDispatch) in the allocator chain.
+
+// When this shim layer is enabled, the route of an allocation is as-follows:
+//
+// [allocator_shim_override_*.h] Intercept malloc() / operator new calls:
+//   The override_* headers define the symbols required to intercept calls to
+//   malloc() and operator new (if not overridden by specific C++ classes).
+//
+// [allocator_shim.cc] Routing allocation calls to the shim:
+//   The headers above route the calls to the internal ShimMalloc(), ShimFree(),
+//   ShimCppNew() etc. methods defined in allocator_shim.cc.
+//   These methods will: (1) forward the allocation call to the front of the
+//   AllocatorDispatch chain. (2) perform security hardenings (e.g., might
+//   call std::new_handler on OOM failure).
+//
+// [allocator_shim_default_dispatch_to_*.cc] The AllocatorDispatch chain:
+//   It is a singly linked list where each element is a struct with function
+//   pointers (|malloc_function|, |free_function|, etc). Normally the chain
+//   consists of a single AllocatorDispatch element, herein called
+//   the "default dispatch", which is statically defined at build time and
+//   ultimately routes the calls to the actual allocator defined by the build
+//   config (tcmalloc, glibc, ...).
+//
+// It is possible to dynamically insert further AllocatorDispatch stages
+// to the front of the chain, for debugging / profiling purposes.
+//
+// All the functions must be thred safe. The shim does not enforce any
+// serialization. This is to route to thread-aware allocators (e.g, tcmalloc)
+// wihout introducing unnecessary perf hits.
+
+struct AllocatorDispatch {
+  using AllocFn = void*(const AllocatorDispatch* self, size_t size);
+  using AllocZeroInitializedFn = void*(const AllocatorDispatch* self,
+                                       size_t n,
+                                       size_t size);
+  using AllocAlignedFn = void*(const AllocatorDispatch* self,
+                               size_t alignment,
+                               size_t size);
+  using ReallocFn = void*(const AllocatorDispatch* self,
+                          void* address,
+                          size_t size);
+  using FreeFn = void(const AllocatorDispatch* self, void* address);
+
+  AllocFn* const alloc_function;
+  AllocZeroInitializedFn* const alloc_zero_initialized_function;
+  AllocAlignedFn* const alloc_aligned_function;
+  ReallocFn* const realloc_function;
+  FreeFn* const free_function;
+
+  const AllocatorDispatch* next;
+
+  // |default_dispatch| is statically defined by one (and only one) of the
+  // allocator_shim_default_dispatch_to_*.cc files, depending on the build
+  // configuration.
+  static const AllocatorDispatch default_dispatch;
+};
+
+// When true makes malloc behave like new, w.r.t calling the new_handler if
+// the allocation fails (see set_new_mode() in Windows).
+BASE_EXPORT void SetCallNewHandlerOnMallocFailure(bool value);
+
+// Allocates |size| bytes or returns nullptr. It does NOT call the new_handler,
+// regardless of SetCallNewHandlerOnMallocFailure().
+BASE_EXPORT void* UncheckedAlloc(size_t size);
+
+// Inserts |dispatch| in front of the allocator chain. This method is NOT
+// thread-safe w.r.t concurrent invocations of InsertAllocatorDispatch().
+// The callers have the responsibility of linearizing the changes to the chain
+// (or more likely call these always on the same thread).
+BASE_EXPORT void InsertAllocatorDispatch(AllocatorDispatch* dispatch);
+
+// Test-only. Rationale: (1) lack of use cases; (2) dealing safely with a
+// removal of arbitrary elements from a singly linked list would require a lock
+// in malloc(), which we really don't want.
+BASE_EXPORT void RemoveAllocatorDispatchForTesting(AllocatorDispatch* dispatch);
+
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
diff --git a/libchrome/base/allocator/allocator_shim_default_dispatch_to_glibc.cc b/libchrome/base/allocator/allocator_shim_default_dispatch_to_glibc.cc
new file mode 100644
index 0000000..02facba
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim_default_dispatch_to_glibc.cc
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Authors. All 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_shim.h"
+
+// This translation unit defines a default dispatch for the allocator shim which
+// routes allocations to libc functions.
+// The code here is strongly inspired from tcmalloc's libc_override_glibc.h.
+
+extern "C" {
+void* __libc_malloc(size_t size);
+void* __libc_calloc(size_t n, size_t size);
+void* __libc_realloc(void* address, size_t size);
+void* __libc_memalign(size_t alignment, size_t size);
+void __libc_free(void* ptr);
+}  // extern "C"
+
+namespace {
+
+using base::allocator::AllocatorDispatch;
+
+void* GlibcMalloc(const AllocatorDispatch*, size_t size) {
+  return __libc_malloc(size);
+}
+
+void* GlibcCalloc(const AllocatorDispatch*, size_t n, size_t size) {
+  return __libc_calloc(n, size);
+}
+
+void* GlibcRealloc(const AllocatorDispatch*, void* address, size_t size) {
+  return __libc_realloc(address, size);
+}
+
+void* GlibcMemalign(const AllocatorDispatch*, size_t alignment, size_t size) {
+  return __libc_memalign(alignment, size);
+}
+
+void GlibcFree(const AllocatorDispatch*, void* address) {
+  __libc_free(address);
+}
+
+}  // namespace
+
+const AllocatorDispatch AllocatorDispatch::default_dispatch = {
+    &GlibcMalloc,   /* alloc_function */
+    &GlibcCalloc,   /* alloc_zero_initialized_function */
+    &GlibcMemalign, /* alloc_aligned_function */
+    &GlibcRealloc,  /* realloc_function */
+    &GlibcFree,     /* free_function */
+    nullptr,        /* next */
+};
diff --git a/libchrome/base/allocator/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc b/libchrome/base/allocator/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc
new file mode 100644
index 0000000..7955cb7
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc
@@ -0,0 +1,57 @@
+// Copyright 2016 The Chromium Authors. All 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_shim.h"
+
+// This translation unit defines a default dispatch for the allocator shim which
+// routes allocations to the original libc functions when using the link-time
+// -Wl,-wrap,malloc approach (see README.md).
+// The __real_X functions here are special symbols that the linker will relocate
+// against the real "X" undefined symbol, so that __real_malloc becomes the
+// equivalent of what an undefined malloc symbol reference would have been.
+// This is the counterpart of allocator_shim_override_linker_wrapped_symbols.h,
+// which routes the __wrap_X functions into the shim.
+
+extern "C" {
+void* __real_malloc(size_t);
+void* __real_calloc(size_t, size_t);
+void* __real_realloc(void*, size_t);
+void* __real_memalign(size_t, size_t);
+void* __real_free(void*);
+}  // extern "C"
+
+namespace {
+
+using base::allocator::AllocatorDispatch;
+
+void* RealMalloc(const AllocatorDispatch*, size_t size) {
+  return __real_malloc(size);
+}
+
+void* RealCalloc(const AllocatorDispatch*, size_t n, size_t size) {
+  return __real_calloc(n, size);
+}
+
+void* RealRealloc(const AllocatorDispatch*, void* address, size_t size) {
+  return __real_realloc(address, size);
+}
+
+void* RealMemalign(const AllocatorDispatch*, size_t alignment, size_t size) {
+  return __real_memalign(alignment, size);
+}
+
+void RealFree(const AllocatorDispatch*, void* address) {
+  __real_free(address);
+}
+
+}  // namespace
+
+const AllocatorDispatch AllocatorDispatch::default_dispatch = {
+    &RealMalloc,   /* alloc_function */
+    &RealCalloc,   /* alloc_zero_initialized_function */
+    &RealMemalign, /* alloc_aligned_function */
+    &RealRealloc,  /* realloc_function */
+    &RealFree,     /* free_function */
+    nullptr,       /* next */
+};
diff --git a/libchrome/base/allocator/allocator_shim_internals.h b/libchrome/base/allocator/allocator_shim_internals.h
new file mode 100644
index 0000000..fc3624c
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim_internals.h
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Authors. All 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_SHIM_INTERNALS_H_
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_INTERNALS_H_
+
+#if defined(__GNUC__)
+
+#include <sys/cdefs.h>  // for __THROW
+
+#ifndef __THROW  // Not a glibc system
+#ifdef _NOEXCEPT  // LLVM libc++ uses noexcept instead
+#define __THROW _NOEXCEPT
+#else
+#define __THROW
+#endif  // !_NOEXCEPT
+#endif
+
+// Shim layer symbols need to be ALWAYS exported, regardless of component build.
+#define SHIM_ALWAYS_EXPORT __attribute__((visibility("default")))
+
+#define SHIM_ALIAS_SYMBOL(fn) __attribute__((alias(#fn)))
+
+#endif  // __GNUC__
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_SHIM_INTERNALS_H_
diff --git a/libchrome/base/allocator/allocator_shim_override_cpp_symbols.h b/libchrome/base/allocator/allocator_shim_override_cpp_symbols.h
new file mode 100644
index 0000000..616716f
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim_override_cpp_symbols.h
@@ -0,0 +1,42 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef BASE_ALLOCATOR_ALLOCATOR_SHIM_OVERRIDE_CPP_SYMBOLS_H_
+#error This header is meant to be included only once by allocator_shim.cc
+#endif
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_OVERRIDE_CPP_SYMBOLS_H_
+
+// Alias the default new/delete C++ symbols to the shim entry points.
+// This file is strongly inspired by tcmalloc's libc_override_redefine.h.
+
+#include <new>
+
+#include "base/allocator/allocator_shim_internals.h"
+
+SHIM_ALWAYS_EXPORT void* operator new(size_t size)
+    SHIM_ALIAS_SYMBOL(ShimCppNew);
+
+SHIM_ALWAYS_EXPORT void operator delete(void* p) __THROW
+    SHIM_ALIAS_SYMBOL(ShimCppDelete);
+
+SHIM_ALWAYS_EXPORT void* operator new[](size_t size)
+    SHIM_ALIAS_SYMBOL(ShimCppNew);
+
+SHIM_ALWAYS_EXPORT void operator delete[](void* p) __THROW
+    SHIM_ALIAS_SYMBOL(ShimCppDelete);
+
+SHIM_ALWAYS_EXPORT void* operator new(size_t size,
+                                      const std::nothrow_t&) __THROW
+    SHIM_ALIAS_SYMBOL(ShimCppNew);
+
+SHIM_ALWAYS_EXPORT void* operator new[](size_t size,
+                                        const std::nothrow_t&) __THROW
+    SHIM_ALIAS_SYMBOL(ShimCppNew);
+
+SHIM_ALWAYS_EXPORT void operator delete(void* p, const std::nothrow_t&) __THROW
+    SHIM_ALIAS_SYMBOL(ShimCppDelete);
+
+SHIM_ALWAYS_EXPORT void operator delete[](void* p,
+                                          const std::nothrow_t&) __THROW
+    SHIM_ALIAS_SYMBOL(ShimCppDelete);
diff --git a/libchrome/base/allocator/allocator_shim_override_libc_symbols.h b/libchrome/base/allocator/allocator_shim_override_libc_symbols.h
new file mode 100644
index 0000000..37b3b4e
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim_override_libc_symbols.h
@@ -0,0 +1,54 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Its purpose is to SHIM_ALIAS_SYMBOL the Libc symbols for malloc/new to the
+// shim layer entry points.
+
+#ifdef BASE_ALLOCATOR_ALLOCATOR_SHIM_OVERRIDE_LIBC_SYMBOLS_H_
+#error This header is meant to be included only once by allocator_shim.cc
+#endif
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_OVERRIDE_LIBC_SYMBOLS_H_
+
+#include <malloc.h>
+
+#include "base/allocator/allocator_shim_internals.h"
+
+extern "C" {
+
+SHIM_ALWAYS_EXPORT void* malloc(size_t size) __THROW
+    SHIM_ALIAS_SYMBOL(ShimMalloc);
+
+SHIM_ALWAYS_EXPORT void free(void* ptr) __THROW
+    SHIM_ALIAS_SYMBOL(ShimFree);
+
+SHIM_ALWAYS_EXPORT void* realloc(void* ptr, size_t size) __THROW
+    SHIM_ALIAS_SYMBOL(ShimRealloc);
+
+SHIM_ALWAYS_EXPORT void* calloc(size_t n, size_t size) __THROW
+    SHIM_ALIAS_SYMBOL(ShimCalloc);
+
+SHIM_ALWAYS_EXPORT void cfree(void* ptr) __THROW
+    SHIM_ALIAS_SYMBOL(ShimFree);
+
+SHIM_ALWAYS_EXPORT void* memalign(size_t align, size_t s) __THROW
+    SHIM_ALIAS_SYMBOL(ShimMemalign);
+
+SHIM_ALWAYS_EXPORT void* valloc(size_t size) __THROW
+    SHIM_ALIAS_SYMBOL(ShimValloc);
+
+SHIM_ALWAYS_EXPORT void* pvalloc(size_t size) __THROW
+    SHIM_ALIAS_SYMBOL(ShimPvalloc);
+
+SHIM_ALWAYS_EXPORT int posix_memalign(void** r, size_t a, size_t s) __THROW
+    SHIM_ALIAS_SYMBOL(ShimPosixMemalign);
+
+// The default dispatch translation unit has to define also the following
+// symbols (unless they are ultimately routed to the system symbols):
+//   void malloc_stats(void);
+//   int mallopt(int, int);
+//   struct mallinfo mallinfo(void);
+//   size_t malloc_size(void*);
+//   size_t malloc_usable_size(const void*);
+
+}  // extern "C"
diff --git a/libchrome/base/allocator/allocator_shim_override_linker_wrapped_symbols.h b/libchrome/base/allocator/allocator_shim_override_linker_wrapped_symbols.h
new file mode 100644
index 0000000..5b85d6e
--- /dev/null
+++ b/libchrome/base/allocator/allocator_shim_override_linker_wrapped_symbols.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef BASE_ALLOCATOR_ALLOCATOR_SHIM_OVERRIDE_LINKER_WRAPPED_SYMBOLS_H_
+#error This header is meant to be included only once by allocator_shim.cc
+#endif
+#define BASE_ALLOCATOR_ALLOCATOR_SHIM_OVERRIDE_LINKER_WRAPPED_SYMBOLS_H_
+
+// This header overrides the __wrap_X symbols when using the link-time
+// -Wl,-wrap,malloc shim-layer approach (see README.md).
+// All references to malloc, free, etc. within the linker unit that gets the
+// -wrap linker flags (e.g., libchrome.so) will be rewritten to the
+// linker as references to __wrap_malloc, __wrap_free, which are defined here.
+
+#include "base/allocator/allocator_shim_internals.h"
+
+extern "C" {
+
+SHIM_ALWAYS_EXPORT void* __wrap_calloc(size_t, size_t)
+    SHIM_ALIAS_SYMBOL(ShimCalloc);
+
+SHIM_ALWAYS_EXPORT void __wrap_free(void*)
+    SHIM_ALIAS_SYMBOL(ShimFree);
+
+SHIM_ALWAYS_EXPORT void* __wrap_malloc(size_t)
+    SHIM_ALIAS_SYMBOL(ShimMalloc);
+
+SHIM_ALWAYS_EXPORT void* __wrap_memalign(size_t, size_t)
+    SHIM_ALIAS_SYMBOL(ShimMemalign);
+
+SHIM_ALWAYS_EXPORT int __wrap_posix_memalign(void**, size_t, size_t)
+    SHIM_ALIAS_SYMBOL(ShimPosixMemalign);
+
+SHIM_ALWAYS_EXPORT void* __wrap_pvalloc(size_t)
+    SHIM_ALIAS_SYMBOL(ShimPvalloc);
+
+SHIM_ALWAYS_EXPORT void* __wrap_realloc(void*, size_t)
+    SHIM_ALIAS_SYMBOL(ShimRealloc);
+
+SHIM_ALWAYS_EXPORT void* __wrap_valloc(size_t)
+    SHIM_ALIAS_SYMBOL(ShimValloc);
+
+}  // extern "C"
diff --git a/libchrome/base/allocator/features.h b/libchrome/base/allocator/features.h
new file mode 100644
index 0000000..eedb0b6
--- /dev/null
+++ b/libchrome/base/allocator/features.h
@@ -0,0 +1,15 @@
+// Generated by build/write_buildflag_header.py
+// From "allocator_features"
+
+#ifndef BASE_ALLOCATOR_FEATURES_H_
+#define BASE_ALLOCATOR_FEATURES_H_
+
+#include "build/buildflag.h"
+
+#if defined(__APPLE__)
+#define BUILDFLAG_INTERNAL_USE_EXPERIMENTAL_ALLOCATOR_SHIM() (0)
+#else
+#define BUILDFLAG_INTERNAL_USE_EXPERIMENTAL_ALLOCATOR_SHIM() (1)
+#endif
+
+#endif  // BASE_ALLOCATOR_FEATURES_H_
diff --git a/libchrome/base/at_exit.cc b/libchrome/base/at_exit.cc
new file mode 100644
index 0000000..cfe4cf9
--- /dev/null
+++ b/libchrome/base/at_exit.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/at_exit.h"
+
+#include <stddef.h>
+#include <ostream>
+#include <utility>
+
+#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()
+    : processing_callbacks_(false), 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_);
+  DCHECK(!g_top_manager->processing_callbacks_);
+  g_top_manager->stack_.push(std::move(task));
+}
+
+// static
+void AtExitManager::ProcessCallbacksNow() {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
+    return;
+  }
+
+  // Callbacks may try to add new callbacks, so run them without holding
+  // |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but
+  // handle it gracefully in release builds so we don't deadlock.
+  std::stack<base::Closure> tasks;
+  {
+    AutoLock lock(g_top_manager->lock_);
+    tasks.swap(g_top_manager->stack_);
+    g_top_manager->processing_callbacks_ = true;
+  }
+
+  while (!tasks.empty()) {
+    base::Closure task = tasks.top();
+    task.Run();
+    tasks.pop();
+  }
+
+  // Expect that all callbacks have been run.
+  DCHECK(g_top_manager->stack_.empty());
+}
+
+AtExitManager::AtExitManager(bool shadow)
+    : processing_callbacks_(false), next_manager_(g_top_manager) {
+  DCHECK(shadow || !g_top_manager);
+  g_top_manager = this;
+}
+
+}  // namespace base
diff --git a/libchrome/base/at_exit.h b/libchrome/base/at_exit.h
new file mode 100644
index 0000000..02e18ed
--- /dev/null
+++ b/libchrome/base/at_exit.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_AT_EXIT_H_
+#define BASE_AT_EXIT_H_
+
+#include <stack>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/macros.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_;
+  bool processing_callbacks_;
+  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/libchrome/base/at_exit_unittest.cc b/libchrome/base/at_exit_unittest.cc
new file mode 100644
index 0000000..cda7340
--- /dev/null
+++ b/libchrome/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/libchrome/base/atomic_ref_count.h b/libchrome/base/atomic_ref_count.h
new file mode 100644
index 0000000..2ab7242
--- /dev/null
+++ b/libchrome/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/libchrome/base/atomic_sequence_num.h b/libchrome/base/atomic_sequence_num.h
new file mode 100644
index 0000000..59b0d25
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/atomicops.h b/libchrome/base/atomicops.h
new file mode 100644
index 0000000..3428fe8
--- /dev/null
+++ b/libchrome/base/atomicops.h
@@ -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.
+
+// 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
+
+#if defined(OS_WIN)
+// TODO(jfb): The MSVC header includes windows.h, which other files end up
+//            relying on. Fix this as part of crbug.com/559247.
+#  include "base/atomicops_internals_x86_msvc.h"
+#else
+#  include "base/atomicops_internals_portable.h"
+#endif
+
+// 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/libchrome/base/atomicops_internals_atomicword_compat.h b/libchrome/base/atomicops_internals_atomicword_compat.h
new file mode 100644
index 0000000..8b000d2
--- /dev/null
+++ b/libchrome/base/atomicops_internals_atomicword_compat.h
@@ -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.
+
+// 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_
+
+#include <stdint.h>
+
+#include "build/build_config.h"
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32_t,
+// 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/libchrome/base/atomicops_internals_portable.h b/libchrome/base/atomicops_internals_portable.h
new file mode 100644
index 0000000..ee034de
--- /dev/null
+++ b/libchrome/base/atomicops_internals_portable.h
@@ -0,0 +1,229 @@
+// 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>
+
+#include "build/build_config.h"
+
+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/libchrome/base/atomicops_internals_x86_msvc.h b/libchrome/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 0000000..9f05b7e
--- /dev/null
+++ b/libchrome/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,196 @@
+// 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"
+#include "build/build_config.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.
+
+static_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/libchrome/base/atomicops_unittest.cc b/libchrome/base/atomicops_unittest.cc
new file mode 100644
index 0000000..7298609
--- /dev/null
+++ b/libchrome/base/atomicops_unittest.cc
@@ -0,0 +1,248 @@
+// 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);
+
+  // Verify that CAS will *not* change "value" if it doesn't match the
+  // expected  number. CAS will always return the actual value of the
+  // variable from before any change.
+  AtomicType fail = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 2);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(1, fail);
+
+  // 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/libchrome/base/auto_reset.h b/libchrome/base/auto_reset.h
new file mode 100644
index 0000000..9116537
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/base.gyp b/libchrome/base/base.gyp
new file mode 100644
index 0000000..a534d5c
--- /dev/null
+++ b/libchrome/base/base.gyp
@@ -0,0 +1,1801 @@
+# Copyright (c) 2012 The Chromium 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': [
+        'allocator/allocator.gyp:allocator',
+        'allocator/allocator.gyp:allocator_features#target',
+        'base_debugging_flags#target',
+        'base_win_features#target',
+        'base_static',
+        'base_build_date#target',
+        '../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"', {
+          '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',
+                ],
+              },
+            }],
+          ],
+        }],
+        ['use_sysroot==0 and (OS == "android" or OS == "linux")', {
+          'link_settings': {
+            'libraries': [
+              # Needed for <atomic> when building with newer C++ library.
+              '-latomic',
+            ],
+          },
+        }],
+        ['OS == "win"', {
+          # Specify delayload for base.dll.
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'powrprof.dll',
+                'setupapi.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'powrprof.lib',
+                'setupapi.lib',
+                'userenv.lib',
+                'winmm.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',
+                  'userenv.lib',
+                  'winmm.lib',
+                ],
+              },
+            },
+          },
+          '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',
+              '$(SDKROOT)/usr/lib/libbsm.dylib',
+            ],
+          },
+        }],
+        ['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',
+              ],
+            }],
+          ],
+        }],
+        ['OS=="ios"', {
+          'sources!': [
+            'sync_socket.h',
+            'sync_socket_posix.cc',
+          ]
+        }],
+        ['use_experimental_allocator_shim==1', {
+          'dependencies': [ 'allocator/allocator.gyp:unified_allocator_shim']
+        }],
+      ],
+      'sources': [
+        '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',
+        '../third_party/icu/icu.gyp:icuuc',
+        '../third_party/icu/icu.gyp:icui18n',
+      ],
+      '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',
+      ],
+    },
+    {
+      # 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': [
+        'allocator/tcmalloc_unittest.cc',
+        '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',
+        'at_exit_unittest.cc',
+        'atomicops_unittest.cc',
+        'barrier_closure_unittest.cc',
+        'base64_unittest.cc',
+        'base64url_unittest.cc',
+        'big_endian_unittest.cc',
+        'bind_unittest.cc',
+        'bind_unittest.nc',
+        'bit_cast_unittest.cc',
+        '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/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',
+        'feature_list_unittest.cc',
+        'file_version_info_win_unittest.cc',
+        'files/dir_reader_posix_unittest.cc',
+        'files/file_locking_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/message_formatter_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/call_with_eh_frame_unittest.mm',
+        'mac/dispatch_source_mach_unittest.cc',
+        'mac/foundation_util_unittest.mm',
+        'mac/mac_util_unittest.mm',
+        'mac/mach_port_broker_unittest.cc',
+        '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_listener_unittest.cc',
+        'memory/memory_pressure_monitor_chromeos_unittest.cc',
+        'memory/memory_pressure_monitor_mac_unittest.cc',
+        'memory/memory_pressure_monitor_win_unittest.cc',
+        'memory/ptr_util_unittest.cc',
+        'memory/ref_counted_memory_unittest.cc',
+        'memory/ref_counted_unittest.cc',
+        'memory/scoped_vector_unittest.cc',
+        'memory/shared_memory_mac_unittest.cc',
+        'memory/shared_memory_unittest.cc',
+        'memory/shared_memory_win_unittest.cc',
+        'memory/singleton_unittest.cc',
+        'memory/weak_ptr_unittest.cc',
+        'memory/weak_ptr_unittest.nc',
+        'message_loop/message_loop_task_runner_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/metrics_hashes_unittest.cc',
+        'metrics/persistent_histogram_allocator_unittest.cc',
+        'metrics/persistent_memory_allocator_unittest.cc',
+        'metrics/persistent_sample_map_unittest.cc',
+        'metrics/sample_map_unittest.cc',
+        'metrics/sample_vector_unittest.cc',
+        'metrics/sparse_histogram_unittest.cc',
+        'metrics/statistics_recorder_unittest.cc',
+        'native_library_unittest.cc',
+        'numerics/safe_numerics_unittest.cc',
+        'observer_list_unittest.cc',
+        'optional_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',
+        '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',
+        'run_loop_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/pattern_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/read_write_lock_unittest.cc',
+        'synchronization/waitable_event_unittest.cc',
+        'synchronization/waitable_event_watcher_unittest.cc',
+        'sys_byteorder_unittest.cc',
+        'sys_info_unittest.cc',
+        'system_monitor/system_monitor_unittest.cc',
+        'task/cancelable_task_tracker_unittest.cc',
+        'task_runner_util_unittest.cc',
+        'task_scheduler/delayed_task_manager_unittest.cc',
+        'task_scheduler/priority_queue_unittest.cc',
+        'task_scheduler/scheduler_lock_unittest.cc',
+        'task_scheduler/scheduler_service_thread_unittest.cc',
+        'task_scheduler/scheduler_worker_unittest.cc',
+        'task_scheduler/scheduler_worker_pool_impl_unittest.cc',
+        'task_scheduler/scheduler_worker_stack_unittest.cc',
+        'task_scheduler/sequence_sort_key_unittest.cc',
+        'task_scheduler/sequence_unittest.cc',
+        'task_scheduler/task_scheduler_impl_unittest.cc',
+        'task_scheduler/task_tracker_unittest.cc',
+        'task_scheduler/test_task_factory.cc',
+        'task_scheduler/test_task_factory.h',
+        'task_scheduler/test_utils.h',
+        'template_util_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/sequenced_task_runner_handle_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_handle_unittest.cc',
+        'win/scoped_process_information_unittest.cc',
+        'win/scoped_variant_unittest.cc',
+        'win/shortcut_unittest.cc',
+        'win/startup_information_unittest.cc',
+        'win/wait_chain_unittest.cc',
+        'win/win_util_unittest.cc',
+        'win/windows_version_unittest.cc',
+        'win/wrapped_window_proc_unittest.cc',
+        '<@(trace_event_test_sources)',
+      ],
+      'dependencies': [
+        'base',
+        'base_i18n',
+        'base_message_loop_tests',
+        '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': [
+        ['cfi_vptr==1 and cfi_cast==1', {
+          'defines': [
+             # TODO(krasin): remove CFI_CAST_CHECK, see https://crbug.com/626794.
+            'CFI_CAST_CHECK',
+          ],
+        }],
+        ['OS == "ios" or OS == "mac"', {
+          'dependencies': [
+            'base_unittests_arc',
+          ],
+        }],
+        ['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/': [
+            # This test needs multiple processes.
+            ['exclude', '^files/file_locking_unittest\\.cc$'],
+            # iOS does not support FilePathWatcher.
+            ['exclude', '^files/file_path_watcher_unittest\\.cc$'],
+            # Only test the iOS-meaningful portion of memory and process_utils.
+            ['exclude', '^memory/discardable_shared_memory_unittest\\.cc$'],
+            ['exclude', '^memory/shared_memory_unittest\\.cc$'],
+            ['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',
+          ],
+          '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',
+          ],
+        }],
+        [ 'OS == "win" and target_arch == "x64"', {
+          'sources': [
+            'profiler/win32_stack_frame_unwinder_unittest.cc',
+          ],
+          'dependencies': [
+            'base_profiler_test_support_library',
+          ],
+        }],
+        ['OS == "win"', {
+          'dependencies': [
+            'scoped_handle_test_dll'
+          ],
+          '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': [
+            ['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'
+          ],
+        }],
+        ['use_experimental_allocator_shim==1', {
+          'sources': [ 'allocator/allocator_shim_unittest.cc']
+        }],
+      ],  # 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'],
+        }],
+        # SyncSocket isn't used on iOS
+        ['OS=="ios"', {
+          'sources!': [
+            'sync_socket_unittest.cc',
+          ],
+        }],
+      ],  # 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/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/icu_test_util.cc',
+        'test/icu_test_util.h',
+        'test/ios/wait_util.h',
+        'test/ios/wait_util.mm',
+        'test/launcher/test_launcher.cc',
+        'test/launcher/test_launcher.h',
+        'test/launcher/test_launcher_tracer.cc',
+        'test/launcher/test_launcher_tracer.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_command_line.cc',
+        'test/scoped_command_line.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_message_loop.cc',
+        'test/test_message_loop.h',
+        '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',
+        }],
+      ],
+    },
+    {
+      # GN version: //base/debug:debugging_flags
+      # Since this generates a file, it must only be referenced in the target
+      # toolchain or there will be multiple rules that generate the header.
+      # When referenced from a target that might be compiled in the host
+      # toolchain, always refer to 'base_debugging_flags#target'.
+      'target_name': 'base_debugging_flags',
+      'includes': [ '../build/buildflag_header.gypi' ],
+      'variables': {
+        'buildflag_header_path': 'base/debug/debugging_flags.h',
+        'buildflag_flags': [
+          'ENABLE_PROFILING=<(profiling)',
+        ],
+      },
+    },
+    {
+      # GN version: //base/win:base_win_features
+      # Since this generates a file, it must only be referenced in the target
+      # toolchain or there will be multiple rules that generate the header.
+      # When referenced from a target that might be compiled in the host
+      # toolchain, always refer to 'base_win_features#target'.
+      'target_name': 'base_win_features',
+      'conditions': [
+        ['OS=="win"', {
+          'includes': [ '../build/buildflag_header.gypi' ],
+          'variables': {
+            'buildflag_header_path': 'base/win/base_features.h',
+            'buildflag_flags': [
+              'SINGLE_MODULE_MODE_HANDLE_VERIFIER=<(single_module_mode_handle_verifier)',
+            ],
+          },
+        }, {
+          'type': 'none',
+        }],
+      ],
+    },
+    {
+      'type': 'none',
+      'target_name': 'base_build_date',
+      'hard_dependency': 1,
+      'actions': [{
+        'action_name': 'generate_build_date_headers',
+        'inputs': [
+          '<(DEPTH)/build/write_build_date_header.py',
+          '<(DEPTH)/build/util/LASTCHANGE'
+        ],
+        'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/base/generated_build_date.h' ],
+        'action': [
+          'python', '<(DEPTH)/build/write_build_date_header.py',
+          '<(SHARED_INTERMEDIATE_DIR)/base/generated_build_date.h',
+          '<(build_type)'
+        ]
+      }],
+      'conditions': [
+        [ 'buildtype == "Official"', {
+          'variables': {
+            'build_type': 'official'
+          }
+        }, {
+          'variables': {
+            'build_type': 'default'
+          }
+        }],
+      ]
+    },
+  ],
+  '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_build_date',
+            'base_debugging_flags#target',
+            'base_static_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',
+                'userenv.lib',
+                'winmm.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',
+                  'userenv.lib',
+                  'winmm.lib',
+                ],
+              },
+            },
+          },
+          # TODO(rvargas): Bug 78117. Remove this.
+          'msvs_disabled_warnings': [
+            4244,
+            4996,
+            4267,
+          ],
+          'sources': [
+            '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 == "win" and target_arch=="x64"', {
+      'targets': [
+        {
+          'target_name': 'base_profiler_test_support_library',
+          # Must be a shared library so that it can be unloaded during testing.
+          'type': 'shared_library',
+          'include_dirs': [
+            '..',
+          ],
+          'sources': [
+            'profiler/test_support_library.cc',
+          ],
+        },
+      ]
+    }],
+    ['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/Callback.java',
+            'android/java/src/org/chromium/base/CommandLine.java',
+            'android/java/src/org/chromium/base/ContentUriUtils.java',
+            'android/java/src/org/chromium/base/ContextUtils.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' ],
+        },
+        {
+          # GN: //base:base_unittests_jni_headers
+          '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_build_config_gen
+          'target_name': 'base_build_config_gen',
+          'type': 'none',
+          'sources': [
+            'android/java/templates/BuildConfig.template',
+          ],
+          'variables': {
+            'package_name': 'org/chromium/base',
+            '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': 'android/java',
+            'jar_excluded_classes': [
+              '*/BuildConfig.class',
+              '*/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_build_config_gen',
+            'base_native_libraries_gen',
+            '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
+            '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
+          ],
+          'all_dependent_settings': {
+            'variables': {
+              'generate_build_config': 1,
+            },
+          },
+          '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' ],
+        },
+        {
+          # TODO(jbudorick): Remove this once we roll to robolectric 3.0 and pull
+          # in the multidex shadow library. crbug.com/522043
+          # GN: //base:base_junit_test_support
+          'target_name': 'base_junit_test_support',
+          'type': 'none',
+          'dependencies': [
+            'base_build_config_gen',
+            '../testing/android/junit/junit_test.gyp:junit_test_support',
+            '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
+          ],
+          'variables': {
+            'src_paths': [
+              '../base/test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java',
+            ],
+          },
+          'includes': [ '../build/host_jar.gypi' ]
+        },
+        {
+          # GN: //base:base_junit_tests
+          'target_name': 'base_junit_tests',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_java_test_support',
+            'base_junit_test_support',
+            '../testing/android/junit/junit_test.gyp:junit_test_support',
+          ],
+          'variables': {
+            'main_class': 'org.chromium.testing.local.JunitTestMain',
+            'src_paths': [
+              '../base/android/junit/',
+              '../base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java',
+              '../base/test/android/junit/src/org/chromium/base/test/util/MinAndroidSdkLevelSkipCheckTest.java',
+              '../base/test/android/junit/src/org/chromium/base/test/util/RestrictionSkipCheckTest.java',
+              '../base/test/android/junit/src/org/chromium/base/test/util/SkipCheckTest.java',
+            ],
+            'test_type': 'junit',
+            'wrapper_script_name': 'helper/<(_target_name)',
+          },
+          'includes': [
+            '../build/android/test_runner.gypi',
+            '../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/android_dlext.h',
+            'android/linker/legacy_linker_jni.cc',
+            'android/linker/legacy_linker_jni.h',
+            'android/linker/linker_jni.cc',
+            'android/linker/linker_jni.h',
+            'android/linker/modern_linker_jni.cc',
+            'android/linker/modern_linker_jni.h',
+          ],
+          # 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',
+          ],
+        },
+        {
+          # GN: //base:base_perftests_apk
+          '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' ],
+        },
+      ],
+      'conditions': [
+        ['test_isolation_mode != "noop"',
+          {
+            'targets': [
+              {
+                'target_name': 'base_unittests_apk_run',
+                'type': 'none',
+                'dependencies': [
+                  'base_unittests_apk',
+                ],
+                'includes': [
+                  '../build/isolate.gypi',
+                ],
+                'sources': [
+                  'base_unittests_apk.isolate',
+                ],
+              },
+            ]
+          }
+        ],
+      ],
+    }],
+    ['OS == "win"', {
+      'targets': [
+        {
+          # 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',
+              ],
+            },
+          },
+        },
+        {
+          'target_name': 'scoped_handle_test_dll',
+          'type': 'loadable_module',
+          'dependencies': [
+            'base',
+          ],
+          'sources': [
+            'win/scoped_handle_test_dll.cc',
+          ],
+        },
+      ],
+    }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'base_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'base_unittests',
+          ],
+          'includes': [
+            '../build/isolate.gypi',
+          ],
+          'sources': [
+            'base_unittests.isolate',
+          ],
+        },
+      ],
+    }],
+    ['OS == "ios" or OS == "mac"', {
+      'targets': [
+        {
+          'target_name': 'base_unittests_arc',
+          'type': 'static_library',
+          'dependencies': [
+            'base',
+            '../testing/gtest.gyp:gtest',
+          ],
+          'sources': [
+            'mac/bind_objc_block_unittest_arc.mm',
+            'mac/scoped_nsobject_unittest_arc.mm'
+          ],
+          'xcode_settings': {
+            'CLANG_ENABLE_OBJC_ARC': 'YES',
+          },
+          'target_conditions': [
+            ['OS == "ios" and _toolset != "host"', {
+              'sources/': [
+                ['include', 'mac/bind_objc_block_unittest_arc\\.mm$'],
+                ['include', 'mac/scoped_nsobject_unittest_arc\\.mm$'],
+              ],
+            }]
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/base/base.gypi b/libchrome/base/base.gypi
new file mode 100644
index 0000000..cb41e79
--- /dev/null
+++ b/libchrome/base/base.gypi
@@ -0,0 +1,1106 @@
+# Copyright (c) 2012 The Chromium 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_check.cc',
+          'allocator/allocator_check.h',
+          'allocator/allocator_extension.cc',
+          'allocator/allocator_extension.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/callback_android.cc',
+          'android/callback_android.h',
+          'android/command_line_android.cc',
+          'android/command_line_android.h',
+          'android/content_uri_utils.cc',
+          'android/content_uri_utils.h',
+          'android/context_utils.cc',
+          'android/context_utils.h',
+          'android/cpu_features.cc',
+          'android/cxa_demangle_stub.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_portable.h',
+          'atomicops_internals_x86_msvc.h',
+          'barrier_closure.cc',
+          'barrier_closure.h',
+          'base64.cc',
+          'base64.h',
+          'base64url.cc',
+          'base64url.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',
+          'big_endian.cc',
+          'big_endian.h',
+          'bind.h',
+          'bind_helpers.cc',
+          'bind_helpers.h',
+          'bind_internal.h',
+          'bit_cast.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/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/close_handle_hook_win.cc',
+          'debug/close_handle_hook_win.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',
+          'feature_list.cc',
+          'feature_list.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',
+          '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/ns_error_util.h',
+          'ios/ns_error_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/call_with_eh_frame.cc',
+          'mac/call_with_eh_frame.h',
+          'mac/call_with_eh_frame_asm.S',
+          '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/mac_logging.h',
+          'mac/mac_logging.mm',
+          'mac/mac_util.h',
+          'mac/mac_util.mm',
+          'mac/mach_logging.cc',
+          'mac/mach_logging.h',
+          'mac/mach_port_broker.h',
+          'mac/mach_port_broker.mm',
+          'mac/mach_port_util.cc',
+          'mac/mach_port_util.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_dispatch_object.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_nsobject.h',
+          'mac/scoped_nsobject.mm',
+          '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/free_deleter.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/ptr_util.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_vector.h',
+          'memory/shared_memory.h',
+          'memory/shared_memory_android.cc',
+          'memory/shared_memory_handle.h',
+          'memory/shared_memory_handle_mac.cc',
+          'memory/shared_memory_handle_win.cc',
+          'memory/shared_memory_mac.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_task_runner.cc',
+          'message_loop/message_loop_task_runner.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/metrics_hashes.cc',
+          'metrics/metrics_hashes.h',
+          'metrics/persistent_histogram_allocator.cc',
+          'metrics/persistent_histogram_allocator.h',
+          'metrics/persistent_memory_allocator.cc',
+          'metrics/persistent_memory_allocator.h',
+          'metrics/persistent_sample_map.cc',
+          'metrics/persistent_sample_map.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',
+          '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',
+          'optional.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',
+          '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/port_provider_mac.cc',
+          'process/port_provider_mac.h',
+          'process/process.h',
+          'process/process_handle.cc',
+          '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_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_nacl.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/native_stack_sampler.cc',
+          'profiler/native_stack_sampler.h',
+          'profiler/native_stack_sampler_posix.cc',
+          'profiler/native_stack_sampler_win.cc',
+          '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/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.cc',
+          'sha1.h',
+          '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/pattern.cc',
+          'strings/pattern.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/read_write_lock.h',
+          'synchronization/read_write_lock_nacl.cc',
+          'synchronization/read_write_lock_posix.cc',
+          'synchronization/read_write_lock_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.mm',
+          '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',
+          'task_scheduler/delayed_task_manager.cc',
+          'task_scheduler/delayed_task_manager.h',
+          'task_scheduler/priority_queue.cc',
+          'task_scheduler/priority_queue.h',
+          'task_scheduler/scheduler_lock.h',
+          'task_scheduler/scheduler_lock_impl.cc',
+          'task_scheduler/scheduler_lock_impl.h',
+          'task_scheduler/scheduler_service_thread.cc',
+          'task_scheduler/scheduler_service_thread.h',
+          'task_scheduler/scheduler_worker.cc',
+          'task_scheduler/scheduler_worker.h',
+          'task_scheduler/scheduler_worker_pool.h',
+          'task_scheduler/scheduler_worker_pool_impl.cc',
+          'task_scheduler/scheduler_worker_pool_impl.h',
+          'task_scheduler/scheduler_worker_stack.cc',
+          'task_scheduler/scheduler_worker_stack.h',
+          'task_scheduler/sequence.cc',
+          'task_scheduler/sequence.h',
+          'task_scheduler/sequence_sort_key.cc',
+          'task_scheduler/sequence_sort_key.h',
+          'task_scheduler/task.cc',
+          'task_scheduler/task.h',
+          'task_scheduler/task_scheduler.cc',
+          'task_scheduler/task_scheduler.h',
+          'task_scheduler/task_scheduler_impl.cc',
+          'task_scheduler/task_scheduler_impl.h',
+          'task_scheduler/task_tracker.cc',
+          'task_scheduler/task_tracker.h',
+          'task_scheduler/task_traits.cc',
+          'task_scheduler/task_traits.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',
+          '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_task_runner_handle.cc',
+          'threading/sequenced_task_runner_handle.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/thread_task_runner_handle.cc',
+          'threading/thread_task_runner_handle.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/object_watcher.cc',
+          'win/object_watcher.h',
+          'win/process_startup_helper.cc',
+          'win/process_startup_helper.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/wait_chain.cc',
+          'win/wait_chain.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': [
+          '..',
+        ],
+        'target_conditions': [
+          ['OS == "mac" or OS == "ios"', {
+            'sources!': [
+              'memory/shared_memory_posix.cc',
+            ],
+          }],
+          ['OS == "ios"', {
+            'sources!': [
+               'memory/discardable_shared_memory.cc',
+               'memory/discardable_shared_memory.h',
+            ],
+          }],
+          ['(<(desktop_linux) == 0 and <(chromeos) == 0) or >(nacl_untrusted_build)==1', {
+              'sources/': [
+                ['exclude', '^nix/'],
+              ],
+          }],
+          ['<(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!': [
+               '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',
+               'synchronization/read_write_lock_posix.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"', {
+            'sources/': [
+              # Pull in specific files for host builds.
+              ['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', '^base_paths_mac\\.'],
+              ['include', '^files/file_util_mac\\.'],
+              ['include', '^file_version_info_mac\\.'],
+              ['include', '^mac/bundle_locations\\.'],
+              ['include', '^mac/call_with_eh_frame\\.'],
+              ['include', '^mac/foundation_util\\.'],
+              ['include', '^mac/mac_logging\\.'],
+              ['include', '^mac/mach_logging\\.'],
+              ['include', '^mac/objc_property_releaser\\.'],
+              ['include', '^mac/scoped_block\\.'],
+              ['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', '^memory/shared_memory_posix\\.'],
+              ['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 unsupported features on iOS.
+              ['exclude', '^files/file_path_watcher.*'],
+              ['exclude', '^threading/platform_thread_internal_posix\\.(h|cc)'],
+              ['exclude', '^trace_event/malloc_dump_provider\\.(h|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': [
+              'profiler/win32_stack_frame_unwinder.cc',
+              'profiler/win32_stack_frame_unwinder.h',
+            ],
+            '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',
+              '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/base_i18n_switches.cc',
+          'i18n/base_i18n_switches.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/message_formatter.cc',
+          'i18n/message_formatter.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/libchrome/base/base.isolate b/libchrome/base/base.isolate
new file mode 100644
index 0000000..079d07d
--- /dev/null
+++ b/libchrome/base/base.isolate
@@ -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.
+{
+  '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',
+    # MSVS runtime libraries.
+    '../build/config/win/msvs_dependencies.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" and asan==1 and component=="shared_library"', {
+      'variables': {
+        'files': [
+          # We only need x.y.z/lib/windows/clang_rt.asan_dynamic-i386.dll,
+          # but since the version (x.y.z) changes, just grab the whole dir.
+          '../third_party/llvm-build/Release+Asserts/lib/clang/',
+        ],
+      },
+    }],
+    ['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)',
+        ],
+      },
+    }],
+    # 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/libchrome/base/base64.cc b/libchrome/base/base64.cc
new file mode 100644
index 0000000..61d8538
--- /dev/null
+++ b/libchrome/base/base64.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/base64.h"
+
+#include <stddef.h>
+
+#include <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/libchrome/base/base64.h b/libchrome/base/base64.h
new file mode 100644
index 0000000..dd72c39
--- /dev/null
+++ b/libchrome/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/libchrome/base/base64_unittest.cc b/libchrome/base/base64_unittest.cc
new file mode 100644
index 0000000..91651f4
--- /dev/null
+++ b/libchrome/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/libchrome/base/base64url.cc b/libchrome/base/base64url.cc
new file mode 100644
index 0000000..942229e
--- /dev/null
+++ b/libchrome/base/base64url.cc
@@ -0,0 +1,102 @@
+// 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/base64url.h"
+
+#include <stddef.h>
+
+#include "base/base64.h"
+#include "base/macros.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/string_util.h"
+
+#include <modp_b64/modp_b64.h>
+
+namespace base {
+
+const char kPaddingChar = '=';
+
+// Base64url maps {+, /} to {-, _} in order for the encoded content to be safe
+// to use in a URL. These characters will be translated by this implementation.
+const char kBase64Chars[] = "+/";
+const char kBase64UrlSafeChars[] = "-_";
+
+void Base64UrlEncode(const StringPiece& input,
+                     Base64UrlEncodePolicy policy,
+                     std::string* output) {
+  Base64Encode(input, output);
+
+  ReplaceChars(*output, "+", "-", output);
+  ReplaceChars(*output, "/", "_", output);
+
+  switch (policy) {
+    case Base64UrlEncodePolicy::INCLUDE_PADDING:
+      // The padding included in |*output| will not be amended.
+      break;
+    case Base64UrlEncodePolicy::OMIT_PADDING:
+      // The padding included in |*output| will be removed.
+      const size_t last_non_padding_pos =
+          output->find_last_not_of(kPaddingChar);
+      if (last_non_padding_pos != std::string::npos)
+        output->resize(last_non_padding_pos + 1);
+
+      break;
+  }
+}
+
+bool Base64UrlDecode(const StringPiece& input,
+                     Base64UrlDecodePolicy policy,
+                     std::string* output) {
+  // Characters outside of the base64url alphabet are disallowed, which includes
+  // the {+, /} characters found in the conventional base64 alphabet.
+  if (input.find_first_of(kBase64Chars) != std::string::npos)
+    return false;
+
+  const size_t required_padding_characters = input.size() % 4;
+  const bool needs_replacement =
+      input.find_first_of(kBase64UrlSafeChars) != std::string::npos;
+
+  switch (policy) {
+    case Base64UrlDecodePolicy::REQUIRE_PADDING:
+      // Fail if the required padding is not included in |input|.
+      if (required_padding_characters > 0)
+        return false;
+      break;
+    case Base64UrlDecodePolicy::IGNORE_PADDING:
+      // Missing padding will be silently appended.
+      break;
+    case Base64UrlDecodePolicy::DISALLOW_PADDING:
+      // Fail if padding characters are included in |input|.
+      if (input.find_first_of(kPaddingChar) != std::string::npos)
+        return false;
+      break;
+  }
+
+  // If the string either needs replacement of URL-safe characters to normal
+  // base64 ones, or additional padding, a copy of |input| needs to be made in
+  // order to make these adjustments without side effects.
+  if (required_padding_characters > 0 || needs_replacement) {
+    std::string base64_input;
+
+    CheckedNumeric<size_t> base64_input_size = input.size();
+    if (required_padding_characters > 0)
+      base64_input_size += 4 - required_padding_characters;
+
+    base64_input.reserve(base64_input_size.ValueOrDie());
+    input.AppendToString(&base64_input);
+
+    // Substitute the base64url URL-safe characters to their base64 equivalents.
+    ReplaceChars(base64_input, "-", "+", &base64_input);
+    ReplaceChars(base64_input, "_", "/", &base64_input);
+
+    // Append the necessary padding characters.
+    base64_input.resize(base64_input_size.ValueOrDie(), '=');
+
+    return Base64Decode(base64_input, output);
+  }
+
+  return Base64Decode(input, output);
+}
+
+}  // namespace base
diff --git a/libchrome/base/base64url.h b/libchrome/base/base64url.h
new file mode 100644
index 0000000..66a4824
--- /dev/null
+++ b/libchrome/base/base64url.h
@@ -0,0 +1,56 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE64URL_H_
+#define BASE_BASE64URL_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+enum class Base64UrlEncodePolicy {
+  // Include the trailing padding in the output, when necessary.
+  INCLUDE_PADDING,
+
+  // Remove the trailing padding from the output.
+  OMIT_PADDING
+};
+
+// Encodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding should be included or omitted from the
+// encoded |*output|. |input| and |*output| may reference the same storage.
+BASE_EXPORT void Base64UrlEncode(const StringPiece& input,
+                                 Base64UrlEncodePolicy policy,
+                                 std::string* output);
+
+enum class Base64UrlDecodePolicy {
+  // Require inputs contain trailing padding if non-aligned.
+  REQUIRE_PADDING,
+
+  // Accept inputs regardless of whether or not they have the correct padding.
+  IGNORE_PADDING,
+
+  // Reject inputs if they contain any trailing padding.
+  DISALLOW_PADDING
+};
+
+// Decodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding will be required, ignored or disallowed
+// altogether. |input| and |*output| may reference the same storage.
+BASE_EXPORT bool Base64UrlDecode(const StringPiece& input,
+                                 Base64UrlDecodePolicy policy,
+                                 std::string* output) WARN_UNUSED_RESULT;
+
+}  // namespace base
+
+#endif  // BASE_BASE64URL_H_
diff --git a/libchrome/base/base64url_unittest.cc b/libchrome/base/base64url_unittest.cc
new file mode 100644
index 0000000..45aa4a8
--- /dev/null
+++ b/libchrome/base/base64url_unittest.cc
@@ -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.
+
+#include "base/base64url.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(Base64UrlTest, EncodeIncludePaddingPolicy) {
+  std::string output;
+  Base64UrlEncode("hello?world", Base64UrlEncodePolicy::INCLUDE_PADDING,
+                  &output);
+
+  // Base64 version: aGVsbG8/d29ybGQ=
+  EXPECT_EQ("aGVsbG8_d29ybGQ=", output);
+
+  // Test for behavior for very short and empty strings.
+  Base64UrlEncode("??", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+  EXPECT_EQ("Pz8=", output);
+
+  Base64UrlEncode("", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+  EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, EncodeOmitPaddingPolicy) {
+  std::string output;
+  Base64UrlEncode("hello?world", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+
+  // base64 version: aGVsbG8/d29ybGQ=
+  EXPECT_EQ("aGVsbG8_d29ybGQ", output);
+
+  // Test for behavior for very short and empty strings.
+  Base64UrlEncode("??", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+  EXPECT_EQ("Pz8", output);
+
+  Base64UrlEncode("", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+  EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeRequirePaddingPolicy) {
+  std::string output;
+  ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+                              Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+
+  ASSERT_FALSE(Base64UrlDecode(
+      "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+  // Test for behavior for very short and empty strings.
+  ASSERT_TRUE(
+      Base64UrlDecode("Pz8=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+  EXPECT_EQ("??", output);
+
+  ASSERT_TRUE(
+      Base64UrlDecode("", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+  EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeIgnorePaddingPolicy) {
+  std::string output;
+  ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ",
+                              Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+
+  // Including the padding is accepted as well.
+  ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+                              Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowPaddingPolicy) {
+  std::string output;
+  ASSERT_FALSE(Base64UrlDecode(
+      "aGVsbG8_d29ybGQ=", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+  // The policy will allow the input when padding has been omitted.
+  ASSERT_TRUE(Base64UrlDecode(
+      "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+  EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowsBase64Alphabet) {
+  std::string output;
+
+  // The "/" character is part of the conventional base64 alphabet, but has been
+  // substituted with "_" in the base64url alphabet.
+  ASSERT_FALSE(Base64UrlDecode(
+      "aGVsbG8/d29ybGQ=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+}
+
+TEST(Base64UrlTest, DecodeDisallowsPaddingOnly) {
+  std::string output;
+
+  ASSERT_FALSE(Base64UrlDecode(
+      "=", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+  ASSERT_FALSE(Base64UrlDecode(
+      "==", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+  ASSERT_FALSE(Base64UrlDecode(
+      "===", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+  ASSERT_FALSE(Base64UrlDecode(
+      "====", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/libchrome/base/base_export.h b/libchrome/base/base_export.h
new file mode 100644
index 0000000..cf7ebd7
--- /dev/null
+++ b/libchrome/base/base_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_BASE_EXPORT_H_
+#define BASE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __declspec(dllexport)
+#else
+#define BASE_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_EXPORT
+#endif  // defined(BASE_IMPLEMENTATION)
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_EXPORT
+#endif
+
+#endif  // BASE_BASE_EXPORT_H_
diff --git a/libchrome/base/base_nacl.gyp b/libchrome/base/base_nacl.gyp
new file mode 100644
index 0000000..30763d4
--- /dev/null
+++ b/libchrome/base/base_nacl.gyp
@@ -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.
+
+{
+  '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',
+            ],
+            'compile_flags': [
+              '-fno-strict-aliasing',
+            ],
+          },
+          'dependencies': [
+            'allocator/allocator.gyp:allocator_features#target',
+            'base.gyp:base_debugging_flags',
+            'base.gyp:base_build_date',
+          ],
+        },
+        {
+          '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': [
+            'allocator/allocator.gyp:allocator_features#target',
+            'base.gyp:base_build_date',
+            '../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',
+
+              # For ForkWithFlags.
+              'process/launch.h',
+              'process/launch_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': [
+            'allocator/allocator.gyp:allocator_features#target',
+            'base.gyp:base_debugging_flags',
+            'base.gyp:base_build_date',
+            '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.gyp:base_build_date',
+            'base_nacl_nonsfi',
+            '../testing/gtest_nacl.gyp:gtest_nacl',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/base/base_switches.cc b/libchrome/base/base_switches.cc
new file mode 100644
index 0000000..f5c6eb3
--- /dev/null
+++ b/libchrome/base/base_switches.cc
@@ -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.
+
+#include "base/base_switches.h"
+#include "build/build_config.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";
+
+// Makes memory allocators keep track of their allocations and context, so a
+// detailed breakdown of memory usage can be presented in chrome://tracing when
+// the memory-infra category is enabled.
+const char kEnableHeapProfiling[]           = "enable-heap-profiling";
+
+// Report native (walk the stack) allocation traces. By default pseudo stacks
+// derived from trace events are reported.
+const char kEnableHeapProfilingModeNative[] = "native";
+
+// 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";
+
+// This option can be used to force field trials when testing changes locally.
+// The argument is a list of name and value pairs, separated by slashes. If a
+// trial name is prefixed with an asterisk, that trial will start activated.
+// For example, the following argument defines two trials, with the second one
+// activated: "GoogleNow/Enable/*MaterialDesignNTP/Default/" This option can
+// also be used by the browser process to send the list of trials to a
+// non-browser process, using the same format. See
+// FieldTrialList::CreateTrialsFromString() in field_trial.h for details.
+const char kForceFieldTrials[]              = "force-fieldtrials";
+
+// 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";
+
+// When running certain tests that spawn child processes, this switch indicates
+// to the test framework that the current process should not initialize ICU to
+// avoid creating any scoped handles too early in startup.
+const char kTestDoNotInitializeIcu[]        = "test-do-not-initialize-icu";
+
+// 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 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";
+
+// Specifies a location for profiling output. This will only work if chrome has
+// been built with the gyp variable profiling=1 or gn arg enable_profiling=true.
+//
+//   {pid} if present will be replaced by the pid of the process.
+//   {count} if present will be incremented each time a profile is generated
+//           for this process.
+// The default is chrome-profile-{pid} for the browser and test-profile-{pid}
+// for tests.
+const char kProfilingFile[] = "profiling-file";
+
+#if defined(OS_WIN)
+// Disables the USB keyboard detection for blocking the OSK on Win8+.
+const char kDisableUsbKeyboardDetect[]      = "disable-usb-keyboard-detect";
+#endif
+
+#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/libchrome/base/base_switches.h b/libchrome/base/base_switches.h
new file mode 100644
index 0000000..0585186
--- /dev/null
+++ b/libchrome/base/base_switches.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.
+
+// 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 kDisableLowEndDeviceMode[];
+extern const char kEnableCrashReporter[];
+extern const char kEnableHeapProfiling[];
+extern const char kEnableHeapProfilingModeNative[];
+extern const char kEnableLowEndDeviceMode[];
+extern const char kForceFieldTrials[];
+extern const char kFullMemoryCrashReport[];
+extern const char kNoErrorDialogs[];
+extern const char kProfilerTiming[];
+extern const char kProfilerTimingDisabledValue[];
+extern const char kProfilingFile[];
+extern const char kTestChildProcess[];
+extern const char kTestDoNotInitializeIcu[];
+extern const char kTraceToFile[];
+extern const char kTraceToFileName[];
+extern const char kV[];
+extern const char kVModule[];
+extern const char kWaitForDebugger[];
+
+#if defined(OS_WIN)
+extern const char kDisableUsbKeyboardDetect[];
+#endif
+
+#if defined(OS_POSIX)
+extern const char kEnableCrashReporterForTesting[];
+#endif
+
+}  // namespace switches
+
+#endif  // BASE_BASE_SWITCHES_H_
diff --git a/libchrome/base/base_unittests.isolate b/libchrome/base/base_unittests.isolate
new file mode 100644
index 0000000..208501f
--- /dev/null
+++ b/libchrome/base/base_unittests.isolate
@@ -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.
+{
+  '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',
+        ],
+      },
+    }],
+    ['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/libchrome/base/bind.h b/libchrome/base/bind.h
new file mode 100644
index 0000000..9cf65b6
--- /dev/null
+++ b/libchrome/base/bind.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_BIND_H_
+#define BASE_BIND_H_
+
+#include "base/bind_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.
+
+namespace base {
+
+template <typename Functor, typename... Args>
+inline base::Callback<MakeUnboundRunType<Functor, Args...>> Bind(
+    Functor&& functor,
+    Args&&... args) {
+  using BindState = internal::MakeBindStateType<Functor, Args...>;
+  using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
+  using Invoker = internal::Invoker<BindState, UnboundRunType>;
+
+  using CallbackType = Callback<UnboundRunType>;
+  return CallbackType(new BindState(std::forward<Functor>(functor),
+                                    std::forward<Args>(args)...),
+                      &Invoker::Run);
+}
+
+}  // namespace base
+
+#endif  // BASE_BIND_H_
diff --git a/libchrome/base/bind_helpers.cc b/libchrome/base/bind_helpers.cc
new file mode 100644
index 0000000..f1fe46d
--- /dev/null
+++ b/libchrome/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/libchrome/base/bind_helpers.h b/libchrome/base/bind_helpers.h
new file mode 100644
index 0000000..93d02e3
--- /dev/null
+++ b/libchrome/base/bind_helpers.h
@@ -0,0 +1,502 @@
+// 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.
+//
+// RetainedRef() accepts a ref counted object and retains a reference to it.
+// When the callback is called, the object is passed as a raw pointer.
+//
+// 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 RetainedRef():
+//
+//    void foo(RefCountedBytes* bytes) {}
+//
+//    scoped_refptr<RefCountedBytes> bytes = ...;
+//    Closure callback = Bind(&foo, base::RetainedRef(bytes));
+//    callback.Run();
+//
+// Without RetainedRef, the scoped_refptr would try to implicitly convert to
+// a raw pointer and fail compilation:
+//
+//    Closure callback = Bind(&foo, bytes); // ERROR!
+//
+//
+// 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(std::unique_ptr<Foo> arg) { }
+//   std::unique_ptr<Foo> CreateFoo() { return std::unique_ptr<Foo>(new Foo());
+//   }
+//
+//   std::unique_ptr<Foo> f(new Foo());
+//
+//   // |cb| is given ownership of Foo(). |f| is now NULL.
+//   // You can use std::move(f) 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 <stddef.h>
+
+#include <type_traits>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
+
+namespace base {
+
+template <typename T>
+struct IsWeakReceiver;
+
+namespace internal {
+
+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>
+class RetainedRefWrapper {
+ public:
+  explicit RetainedRefWrapper(T* o) : ptr_(o) {}
+  explicit RetainedRefWrapper(scoped_refptr<T> o) : ptr_(std::move(o)) {}
+  T* get() const { return ptr_.get(); }
+ private:
+  scoped_refptr<T> ptr_;
+};
+
+template <typename T>
+struct IgnoreResultHelper {
+  explicit IgnoreResultHelper(T functor) : functor_(std::move(functor)) {}
+  explicit operator bool() const { return !!functor_; }
+
+  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 std::unique_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(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 move constructor, however
+//     the type will need to be specifically whitelisted in order for it to be
+//     bound to a Callback. We guard this explicitly at the call of Passed()
+//     to make for clear errors. Things not given to Passed() will be forwarded
+//     and stored by value which will not work for general move-only types.
+//  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_(std::move(scoper)) {}
+  PassedWrapper(PassedWrapper&& other)
+      : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
+  T Take() const {
+    CHECK(is_valid_);
+    is_valid_ = false;
+    return std::move(scoper_);
+  }
+
+ private:
+  mutable bool is_valid_;
+  mutable T scoper_;
+};
+
+// Unwrap the stored parameters for the wrappers above.
+template <typename T>
+T&& Unwrap(T&& o) {
+  return std::forward<T>(o);
+}
+
+template <typename T>
+T* Unwrap(const UnretainedWrapper<T>& unretained) {
+  return unretained.get();
+}
+
+template <typename T>
+const T& Unwrap(const ConstRefWrapper<T>& const_ref) {
+  return const_ref.get();
+}
+
+template <typename T>
+T* Unwrap(const RetainedRefWrapper<T>& o) {
+  return o.get();
+}
+
+template <typename T>
+T* Unwrap(const OwnedWrapper<T>& o) {
+  return o.get();
+}
+
+template <typename T>
+T Unwrap(const PassedWrapper<T>& o) {
+  return o.Take();
+}
+
+// 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 is_method, typename... Args>
+struct IsWeakMethod : std::false_type {};
+
+template <typename T, typename... Args>
+struct IsWeakMethod<true, T, Args...> : IsWeakReceiver<T> {};
+
+// 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...>> {
+  using Type = TypeList<T, List...>;
+};
+
+template <>
+struct DropTypeListItemImpl<0, TypeList<>> {
+  using Type = TypeList<>;
+};
+
+// 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 TakeTypeListItem implementation.
+template <size_t n, typename List, typename... Accum>
+struct TakeTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
+    : TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
+
+template <typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
+  using Type = TypeList<Accum...>;
+};
+
+template <typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
+  using Type = TypeList<Accum...>;
+};
+
+// A type-level function that takes first |n| list item from given TypeList.
+// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
+// TypeList<A, B, C>.
+template <size_t n, typename List>
+using TakeTypeListItem = typename TakeTypeListItemImpl<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...>> {
+  using Type = TypeList<Types1..., Types2...>;
+};
+
+// 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...>> {
+  // MSVC 2013 doesn't support Type Alias of function types.
+  // Revisit this after we update it to newer version.
+  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;
+
+// Used for ExtractArgs and ExtractReturnType.
+template <typename Signature>
+struct ExtractArgsImpl;
+
+template <typename R, typename... Args>
+struct ExtractArgsImpl<R(Args...)> {
+  using ReturnType = R;
+  using ArgsList = TypeList<Args...>;
+};
+
+// A type-level function that extracts function arguments into a TypeList.
+// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
+template <typename Signature>
+using ExtractArgs = typename ExtractArgsImpl<Signature>::ArgsList;
+
+// A type-level function that extracts the return type of a function.
+// E.g. ExtractReturnType<R(A, B, C)> is evaluated to R.
+template <typename Signature>
+using ExtractReturnType = typename ExtractArgsImpl<Signature>::ReturnType;
+
+}  // namespace internal
+
+template <typename T>
+static inline internal::UnretainedWrapper<T> Unretained(T* o) {
+  return internal::UnretainedWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::RetainedRefWrapper<T> RetainedRef(T* o) {
+  return internal::RetainedRefWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::RetainedRefWrapper<T> RetainedRef(scoped_refptr<T> o) {
+  return internal::RetainedRefWrapper<T>(std::move(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 an rvalue and
+// is best suited for use with the return value of a function or other temporary
+// rvalues. The second takes a pointer to the scoper and is just syntactic sugar
+// to avoid having to write Passed(std::move(scoper)).
+//
+// Both versions of Passed() prevent T from being an lvalue reference. The first
+// via use of enable_if, and the second takes a T* which will not bind to T&.
+template <typename T,
+          typename std::enable_if<!std::is_lvalue_reference<T>::value>::type* =
+              nullptr>
+static inline internal::PassedWrapper<T> Passed(T&& scoper) {
+  return internal::PassedWrapper<T>(std::move(scoper));
+}
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T* scoper) {
+  return internal::PassedWrapper<T>(std::move(*scoper));
+}
+
+template <typename T>
+static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
+  return internal::IgnoreResultHelper<T>(std::move(data));
+}
+
+BASE_EXPORT void DoNothing();
+
+template<typename T>
+void DeletePointer(T* obj) {
+  delete obj;
+}
+
+// An injection point to control |this| pointer behavior on a method invocation.
+// If IsWeakReceiver<> is true_type for |T| and |T| is used for a receiver of a
+// method, base::Bind cancels the method invocation if the receiver is tested as
+// false.
+// E.g. Foo::bar() is not called:
+//   struct Foo : base::SupportsWeakPtr<Foo> {
+//     void bar() {}
+//   };
+//
+//   WeakPtr<Foo> oo = nullptr;
+//   base::Bind(&Foo::bar, oo).Run();
+template <typename T>
+struct IsWeakReceiver : std::false_type {};
+
+template <typename T>
+struct IsWeakReceiver<internal::ConstRefWrapper<T>> : IsWeakReceiver<T> {};
+
+template <typename T>
+struct IsWeakReceiver<WeakPtr<T>> : std::true_type {};
+
+}  // namespace base
+
+#endif  // BASE_BIND_HELPERS_H_
diff --git a/libchrome/base/bind_internal.h b/libchrome/base/bind_internal.h
new file mode 100644
index 0000000..3ce4417
--- /dev/null
+++ b/libchrome/base/bind_internal.h
@@ -0,0 +1,452 @@
+// 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 <stddef.h>
+
+#include <tuple>
+#include <type_traits>
+
+#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"
+
+namespace base {
+namespace internal {
+
+// See base/callback.h for user documentation.
+//
+//
+// CONCEPTS:
+//  Functor -- A movable type representing something that should be called.
+//             All function pointers and Callback<> are functors even if the
+//             invocation syntax differs.
+//  RunType -- A function type (as opposed to function _pointer_ type) for
+//             a Callback<>::Run().  Usually just a convenience typedef.
+//  (Bound)Args -- A set of types that stores the arguments.
+//
+// Types:
+//  ForceVoidReturn<> -- Helper class for translating function signatures to
+//                       equivalent forms with a "void" return type.
+//  FunctorTraits<> -- Type traits used to determine the correct RunType and
+//                     invocation manner for a Functor.  This is where function
+//                     signature adapters are applied.
+//  InvokeHelper<> -- Take a Functor + arguments and actully invokes it.
+//                    Handle the differing syntaxes needed for WeakPtr<>
+//                    support.  This is separate from Invoker to avoid creating
+//                    multiple version of Invoker<>.
+//  Invoker<> -- Unwraps the curried parameters and executes the Functor.
+//  BindState<> -- Stores the curried parameters, and is the main entry point
+//                 into the Bind() system.
+
+template <typename...>
+struct make_void {
+  using type = void;
+};
+
+// A clone of C++17 std::void_t.
+// Unlike the original version, we need |make_void| as a helper struct to avoid
+// a C++14 defect.
+// ref: http://en.cppreference.com/w/cpp/types/void_t
+// ref: http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
+template <typename... Ts>
+using void_t = typename make_void<Ts...>::type;
+
+template <typename Callable,
+          typename Signature = decltype(&Callable::operator())>
+struct ExtractCallableRunTypeImpl;
+
+template <typename Callable, typename R, typename... Args>
+struct ExtractCallableRunTypeImpl<Callable, R(Callable::*)(Args...) const> {
+  using Type = R(Args...);
+};
+
+// Evaluated to RunType of the given callable type.
+// Example:
+//   auto f = [](int, char*) { return 0.1; };
+//   ExtractCallableRunType<decltype(f)>
+//   is evaluated to
+//   double(int, char*);
+template <typename Callable>
+using ExtractCallableRunType =
+    typename ExtractCallableRunTypeImpl<Callable>::Type;
+
+// IsConvertibleToRunType<Functor> is std::true_type if |Functor| has operator()
+// and convertible to the corresponding function pointer. Otherwise, it's
+// std::false_type.
+// Example:
+//   IsConvertibleToRunType<void(*)()>::value is false.
+//
+//   struct Foo {};
+//   IsConvertibleToRunType<void(Foo::*)()>::value is false.
+//
+//   auto f = []() {};
+//   IsConvertibleToRunType<decltype(f)>::value is true.
+//
+//   int i = 0;
+//   auto g = [i]() {};
+//   IsConvertibleToRunType<decltype(g)>::value is false.
+template <typename Functor, typename SFINAE = void>
+struct IsConvertibleToRunType : std::false_type {};
+
+template <typename Callable>
+struct IsConvertibleToRunType<Callable, void_t<decltype(&Callable::operator())>>
+    : std::is_convertible<Callable, ExtractCallableRunType<Callable>*> {};
+
+// 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 : std::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...>
+    : std::conditional<NeedsScopedRefptrButGetsRawPtr<T>::value,
+                       std::true_type,
+                       HasRefCountedTypeAsRawPtr<Args...>>::type {};
+
+// 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...)> {
+  using RunType = void(Args...);
+};
+
+// FunctorTraits<>
+//
+// See description at top of file.
+template <typename Functor, typename SFINAE = void>
+struct FunctorTraits;
+
+// For a callable type that is convertible to the corresponding function type.
+// This specialization is intended to allow binding captureless lambdas by
+// base::Bind(), based on the fact that captureless lambdas can be convertible
+// to the function type while capturing lambdas can't.
+template <typename Functor>
+struct FunctorTraits<
+    Functor> {
+  using RunType = ExtractCallableRunType<Functor>;
+  static constexpr bool is_method = false;
+  static constexpr bool is_nullable = false;
+
+  template <typename... RunArgs>
+  static ExtractReturnType<RunType>
+  Invoke(const Functor& functor, RunArgs&&... args) {
+    return functor(std::forward<RunArgs>(args)...);
+  }
+};
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R (*)(Args...)> {
+  using RunType = R(Args...);
+  static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
+
+  template <typename... RunArgs>
+  static R Invoke(R (*function)(Args...), RunArgs&&... args) {
+    return function(std::forward<RunArgs>(args)...);
+  }
+};
+
+#if defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__stdcall*)(Args...)> {
+  using RunType = R(Args...);
+  static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
+
+  template <typename... RunArgs>
+  static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) {
+    return function(std::forward<RunArgs>(args)...);
+  }
+};
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__fastcall*)(Args...)> {
+  using RunType = R(Args...);
+  static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
+
+  template <typename... RunArgs>
+  static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) {
+    return function(std::forward<RunArgs>(args)...);
+  }
+};
+
+#endif  // defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
+
+// For methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...)> {
+  using RunType = R(Receiver*, Args...);
+  static constexpr bool is_method = true;
+  static constexpr bool is_nullable = true;
+
+  template <typename ReceiverPtr, typename... RunArgs>
+  static R Invoke(R (Receiver::*method)(Args...),
+                  ReceiverPtr&& receiver_ptr,
+                  RunArgs&&... args) {
+    // Clang skips CV qualifier check on a method pointer invocation when the
+    // receiver is a subclass. Store the receiver into a const reference to
+    // T to ensure the CV check works.
+    // https://llvm.org/bugs/show_bug.cgi?id=27037
+    Receiver& receiver = *receiver_ptr;
+    return (receiver.*method)(std::forward<RunArgs>(args)...);
+  }
+};
+
+// For const methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) const> {
+  using RunType = R(const Receiver*, Args...);
+  static constexpr bool is_method = true;
+  static constexpr bool is_nullable = true;
+
+  template <typename ReceiverPtr, typename... RunArgs>
+  static R Invoke(R (Receiver::*method)(Args...) const,
+                  ReceiverPtr&& receiver_ptr,
+                  RunArgs&&... args) {
+    // Clang skips CV qualifier check on a method pointer invocation when the
+    // receiver is a subclass. Store the receiver into a const reference to
+    // T to ensure the CV check works.
+    // https://llvm.org/bugs/show_bug.cgi?id=27037
+    const Receiver& receiver = *receiver_ptr;
+    return (receiver.*method)(std::forward<RunArgs>(args)...);
+  }
+};
+
+// For IgnoreResults.
+template <typename T>
+struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
+  using RunType =
+      typename ForceVoidReturn<typename FunctorTraits<T>::RunType>::RunType;
+
+  template <typename IgnoreResultType, typename... RunArgs>
+  static void Invoke(IgnoreResultType&& ignore_result_helper,
+                     RunArgs&&... args) {
+    FunctorTraits<T>::Invoke(ignore_result_helper.functor_,
+                             std::forward<RunArgs>(args)...);
+  }
+};
+
+// For Callbacks.
+template <typename R, typename... Args, CopyMode copy_mode>
+struct FunctorTraits<Callback<R(Args...), copy_mode>> {
+  using RunType = R(Args...);
+  static constexpr bool is_method = false;
+  static constexpr bool is_nullable = true;
+
+  template <typename CallbackType, typename... RunArgs>
+  static R Invoke(CallbackType&& callback, RunArgs&&... args) {
+    DCHECK(!callback.is_null());
+    return std::forward<CallbackType>(callback).Run(
+        std::forward<RunArgs>(args)...);
+  }
+};
+
+// InvokeHelper<>
+//
+// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// WeakCalls need special syntax that is applied to the first argument to check
+// if they should no-op themselves.
+template <bool is_weak_call, typename ReturnType>
+struct InvokeHelper;
+
+template <typename ReturnType>
+struct InvokeHelper<false, ReturnType> {
+  template <typename Functor, typename... RunArgs>
+  static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) {
+    using Traits = FunctorTraits<typename std::decay<Functor>::type>;
+    return Traits::Invoke(std::forward<Functor>(functor),
+                          std::forward<RunArgs>(args)...);
+  }
+};
+
+template <typename ReturnType>
+struct InvokeHelper<true, ReturnType> {
+  // WeakCalls are only supported for functions with a void return type.
+  // Otherwise, the function result would be undefined if the the WeakPtr<>
+  // is invalidated.
+  static_assert(std::is_void<ReturnType>::value,
+                "weak_ptrs can only bind to methods without return values");
+
+  template <typename Functor, typename BoundWeakPtr, typename... RunArgs>
+  static inline void MakeItSo(Functor&& functor,
+                              BoundWeakPtr&& weak_ptr,
+                              RunArgs&&... args) {
+    if (!weak_ptr)
+      return;
+    using Traits = FunctorTraits<typename std::decay<Functor>::type>;
+    Traits::Invoke(std::forward<Functor>(functor),
+                   std::forward<BoundWeakPtr>(weak_ptr),
+                   std::forward<RunArgs>(args)...);
+  }
+};
+
+// Invoker<>
+//
+// See description at the top of the file.
+template <typename StorageType, typename UnboundRunType>
+struct Invoker;
+
+template <typename StorageType, typename R, typename... UnboundArgs>
+struct Invoker<StorageType, R(UnboundArgs...)> {
+  static R Run(BindStateBase* base, UnboundArgs&&... unbound_args) {
+    // 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.
+    const StorageType* storage = static_cast<StorageType*>(base);
+    static constexpr size_t num_bound_args =
+        std::tuple_size<decltype(storage->bound_args_)>::value;
+    return RunImpl(storage->functor_,
+                   storage->bound_args_,
+                   MakeIndexSequence<num_bound_args>(),
+                   std::forward<UnboundArgs>(unbound_args)...);
+  }
+
+ private:
+  template <typename Functor, typename BoundArgsTuple, size_t... indices>
+  static inline R RunImpl(Functor&& functor,
+                          BoundArgsTuple&& bound,
+                          IndexSequence<indices...>,
+                          UnboundArgs&&... unbound_args) {
+    static constexpr bool is_method =
+        FunctorTraits<typename std::decay<Functor>::type>::is_method;
+
+    using DecayedArgsTuple = typename std::decay<BoundArgsTuple>::type;
+    static constexpr bool is_weak_call =
+        IsWeakMethod<is_method,
+                     typename std::tuple_element<
+                         indices,
+                         DecayedArgsTuple>::type...>::value;
+
+    return InvokeHelper<is_weak_call, R>::MakeItSo(
+        std::forward<Functor>(functor),
+        Unwrap(base::get<indices>(std::forward<BoundArgsTuple>(bound)))...,
+        std::forward<UnboundArgs>(unbound_args)...);
+  }
+};
+
+// Used to implement MakeUnboundRunType.
+template <typename Functor, typename... BoundArgs>
+struct MakeUnboundRunTypeImpl {
+  using RunType =
+      typename FunctorTraits<typename std::decay<Functor>::type>::RunType;
+  using ReturnType = ExtractReturnType<RunType>;
+  using Args = ExtractArgs<RunType>;
+  using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), Args>;
+  using Type = MakeFunctionType<ReturnType, UnboundArgs>;
+};
+template <typename Functor>
+typename std::enable_if<FunctorTraits<Functor>::is_nullable, bool>::type
+IsNull(const Functor& functor) {
+  return !functor;
+}
+
+template <typename Functor>
+typename std::enable_if<!FunctorTraits<Functor>::is_nullable, bool>::type
+IsNull(const Functor&) {
+  return false;
+}
+
+// BindState<>
+//
+// This stores all the state passed into Bind().
+template <typename Functor, typename... BoundArgs>
+struct BindState final : BindStateBase {
+  template <typename ForwardFunctor, typename... ForwardBoundArgs>
+  explicit BindState(ForwardFunctor&& functor, ForwardBoundArgs&&... bound_args)
+      : BindStateBase(&Destroy),
+      functor_(std::forward<ForwardFunctor>(functor)),
+        bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
+    DCHECK(!IsNull(functor_));
+  }
+
+  Functor functor_;
+  std::tuple<BoundArgs...> bound_args_;
+
+ private:
+  ~BindState() {}
+
+  static void Destroy(BindStateBase* self) {
+    delete static_cast<BindState*>(self);
+  }
+};
+
+// Used to implement MakeBindStateType.
+template <bool is_method, typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl;
+
+template <typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> {
+  static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
+                "A parameter is a refcounted type and needs scoped_refptr.");
+  using Type = BindState<typename std::decay<Functor>::type,
+                         typename std::decay<BoundArgs>::type...>;
+};
+
+template <typename Functor>
+struct MakeBindStateTypeImpl<true, Functor> {
+  using Type = BindState<typename std::decay<Functor>::type>;
+};
+
+template <typename Functor, typename Receiver, typename... BoundArgs>
+struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
+  static_assert(
+      !std::is_array<typename std::remove_reference<Receiver>::type>::value,
+      "First bound argument to a method cannot be an array.");
+  static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
+                "A parameter is a refcounted type and needs scoped_refptr.");
+
+ private:
+  using DecayedReceiver = typename std::decay<Receiver>::type;
+
+ public:
+  using Type = BindState<
+      typename std::decay<Functor>::type,
+      typename std::conditional<
+          std::is_pointer<DecayedReceiver>::value,
+          scoped_refptr<typename std::remove_pointer<DecayedReceiver>::type>,
+          DecayedReceiver>::type,
+      typename std::decay<BoundArgs>::type...>;
+};
+
+template <typename Functor, typename... BoundArgs>
+using MakeBindStateType = typename MakeBindStateTypeImpl<
+    FunctorTraits<typename std::decay<Functor>::type>::is_method,
+    Functor,
+    BoundArgs...>::Type;
+
+}  // namespace internal
+
+// Returns a RunType of bound functor.
+// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C).
+template <typename Functor, typename... BoundArgs>
+using MakeUnboundRunType =
+    typename internal::MakeUnboundRunTypeImpl<Functor, BoundArgs...>::Type;
+
+}  // namespace base
+
+#endif  // BASE_BIND_INTERNAL_H_
diff --git a/libchrome/base/bind_unittest.cc b/libchrome/base/bind_unittest.cc
new file mode 100644
index 0000000..ba5113b
--- /dev/null
+++ b/libchrome/base/bind_unittest.cc
@@ -0,0 +1,1117 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <memory>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "build/build_config.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());
+  MOCK_CONST_METHOD0(VoidConstMethod0, void());
+
+  MOCK_METHOD0(IntMethod0, int());
+  MOCK_CONST_METHOD0(IntConstMethod0, int());
+
+ 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());
+  MOCK_CONST_METHOD0(Release, bool());
+
+ 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:
+  virtual ~Parent() {}
+  void AddRef() const {}
+  void Release() const {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class Child : public Parent {
+ public:
+  ~Child() override {}
+  void VirtualSet() override { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+  virtual ~NoRefParent() {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class NoRefChild : public NoRefParent {
+ public:
+  ~NoRefChild() override {}
+ private:
+  void VirtualSet() override { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+// Used for probing the number of copies and moves that occur if a type must be
+// coerced during argument forwarding in the Run() methods.
+struct DerivedCopyMoveCounter {
+  DerivedCopyMoveCounter(int* copies,
+                         int* assigns,
+                         int* move_constructs,
+                         int* move_assigns)
+      : copies_(copies),
+        assigns_(assigns),
+        move_constructs_(move_constructs),
+        move_assigns_(move_assigns) {}
+  int* copies_;
+  int* assigns_;
+  int* move_constructs_;
+  int* move_assigns_;
+};
+
+// Used for probing the number of copies and moves in an argument.
+class CopyMoveCounter {
+ public:
+  CopyMoveCounter(int* copies,
+                  int* assigns,
+                  int* move_constructs,
+                  int* move_assigns)
+      : copies_(copies),
+        assigns_(assigns),
+        move_constructs_(move_constructs),
+        move_assigns_(move_assigns) {}
+
+  CopyMoveCounter(const CopyMoveCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_),
+        move_constructs_(other.move_constructs_),
+        move_assigns_(other.move_assigns_) {
+    (*copies_)++;
+  }
+
+  CopyMoveCounter(CopyMoveCounter&& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_),
+        move_constructs_(other.move_constructs_),
+        move_assigns_(other.move_assigns_) {
+    (*move_constructs_)++;
+  }
+
+  // Probing for copies from coercion.
+  explicit CopyMoveCounter(const DerivedCopyMoveCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_),
+        move_constructs_(other.move_constructs_),
+        move_assigns_(other.move_assigns_) {
+    (*copies_)++;
+  }
+
+  // Probing for moves from coercion.
+  explicit CopyMoveCounter(DerivedCopyMoveCounter&& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_),
+        move_constructs_(other.move_constructs_),
+        move_assigns_(other.move_assigns_) {
+    (*move_constructs_)++;
+  }
+
+  const CopyMoveCounter& operator=(const CopyMoveCounter& rhs) {
+    copies_ = rhs.copies_;
+    assigns_ = rhs.assigns_;
+    move_constructs_ = rhs.move_constructs_;
+    move_assigns_ = rhs.move_assigns_;
+
+    (*assigns_)++;
+
+    return *this;
+  }
+
+  const CopyMoveCounter& operator=(CopyMoveCounter&& rhs) {
+    copies_ = rhs.copies_;
+    assigns_ = rhs.assigns_;
+    move_constructs_ = rhs.move_constructs_;
+    move_assigns_ = rhs.move_assigns_;
+
+    (*move_assigns_)++;
+
+    return *this;
+  }
+
+  int copies() const {
+    return *copies_;
+  }
+
+ private:
+  int* copies_;
+  int* assigns_;
+  int* move_constructs_;
+  int* move_assigns_;
+};
+
+// Used for probing the number of copies in an argument. The instance is a
+// copyable and non-movable type.
+class CopyCounter {
+ public:
+  CopyCounter(int* copies, int* assigns)
+      : counter_(copies, assigns, nullptr, nullptr) {}
+  CopyCounter(const CopyCounter& other) : counter_(other.counter_) {}
+  CopyCounter& operator=(const CopyCounter& other) {
+    counter_ = other.counter_;
+    return *this;
+  }
+
+  explicit CopyCounter(const DerivedCopyMoveCounter& other) : counter_(other) {}
+
+  int copies() const { return counter_.copies(); }
+
+ private:
+  CopyMoveCounter counter_;
+};
+
+// Used for probing the number of moves in an argument. The instance is a
+// non-copyable and movable type.
+class MoveCounter {
+ public:
+  MoveCounter(int* move_constructs, int* move_assigns)
+      : counter_(nullptr, nullptr, move_constructs, move_assigns) {}
+  MoveCounter(MoveCounter&& other) : counter_(std::move(other.counter_)) {}
+  MoveCounter& operator=(MoveCounter&& other) {
+    counter_ = std::move(other.counter_);
+    return *this;
+  }
+
+  explicit MoveCounter(DerivedCopyMoveCounter&& other)
+      : counter_(std::move(other)) {}
+
+ private:
+  CopyMoveCounter counter_;
+};
+
+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;
+}
+
+// Some test functions that we can Bind to.
+template <typename T>
+T PolymorphicIdentity(T t) {
+  return t;
+}
+
+template <typename... Ts>
+struct VoidPolymorphic {
+  static void Run(Ts... 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 CopyMoveCounter& 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() {
+    static_func_mock_ptr->VoidMethod0();
+  }
+
+  static int IntFunc0() { 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()> 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()> 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(4);
+  EXPECT_CALL(has_ref_, Release()).Times(4);
+  EXPECT_CALL(has_ref_, VoidMethod0()).Times(2);
+  EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
+
+  Closure normal_cb = Bind(&VoidFunc0);
+  Callback<NoRef*()> 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()> normal_cb = Bind(&IntFunc0);
+  Callback<int()> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
+  Callback<int()> const_method_nonconst_obj_cb =
+      Bind(&HasRef::IntConstMethod0, &has_ref_);
+  Callback<int()> 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()> bind_primitive_cb = Bind(&Identity, n);
+  EXPECT_EQ(n, bind_primitive_cb.Run());
+
+  Callback<int*()> bind_primitive_pointer_cb =
+      Bind(&PolymorphicIdentity<int*>, &n);
+  EXPECT_EQ(&n, bind_primitive_pointer_cb.Run());
+
+  Callback<int()> bind_int_literal_cb = Bind(&Identity, 3);
+  EXPECT_EQ(3, bind_int_literal_cb.Run());
+
+  Callback<const char*()> bind_string_literal_cb =
+      Bind(&CStringIdentity, "hi");
+  EXPECT_STREQ("hi", bind_string_literal_cb.Run());
+
+  Callback<int()> bind_template_function_cb =
+      Bind(&PolymorphicIdentity<int>, 4);
+  EXPECT_EQ(4, bind_template_function_cb.Run());
+
+  NoRefParent p;
+  p.value = 5;
+  Callback<int()> bind_object_cb = Bind(&UnwrapNoRefParent, p);
+  EXPECT_EQ(5, bind_object_cb.Run());
+
+  IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123);
+  Callback<IncompleteType*()> 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()> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
+  EXPECT_EQ(6, bind_promotes_cb.Run());
+
+  c.value = 7;
+  Callback<int()> bind_pointer_promotes_cb =
+      Bind(&UnwrapNoRefParentPtr, &c);
+  EXPECT_EQ(7, bind_pointer_promotes_cb.Run());
+
+  c.value = 8;
+  Callback<int()> 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(&VoidPolymorphic<int>::Run);
+  Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic<int*>::Run);
+  Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic<int&>::Run);
+  Callback<void(const int&)> unbound_const_ref_cb =
+      Bind(&VoidPolymorphic<const int&>::Run);
+  Callback<void(int[])> unbound_unsized_array_cb =
+      Bind(&VoidPolymorphic<int[]>::Run);
+  Callback<void(int[2])> unbound_sized_array_cb =
+      Bind(&VoidPolymorphic<int[2]>::Run);
+  Callback<void(int[][2])> unbound_array_of_arrays_cb =
+      Bind(&VoidPolymorphic<int[][2]>::Run);
+
+  Callback<void(int&)> unbound_ref_with_bound_arg =
+      Bind(&VoidPolymorphic<int, int&>::Run, 1);
+}
+
+// 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()> 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()> 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()> array_cb = Bind(&ArrayGet, array, 1);
+  EXPECT_EQ(1, array_cb.Run());
+
+  Callback<int()> 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());
+}
+
+// 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()> method_cb =
+      Bind(&NoRef::VoidMethod0, Unretained(&no_ref_));
+  method_cb.Run();
+
+  Callback<void()> const_method_cb =
+      Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
+  const_method_cb.Run();
+
+  Callback<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()> copy_cb = Bind(&Identity, n);
+  Callback<int()> 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;
+  int move_constructs = 0;
+  int move_assigns = 0;
+  CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns);
+  Callback<int()> all_const_ref_cb =
+      Bind(&GetCopies, ConstRef(counter));
+  EXPECT_EQ(0, all_const_ref_cb.Run());
+  EXPECT_EQ(0, copies);
+  EXPECT_EQ(0, assigns);
+  EXPECT_EQ(0, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+}
+
+TEST_F(BindTest, ScopedRefptr) {
+  EXPECT_CALL(has_ref_, AddRef()).Times(1);
+  EXPECT_CALL(has_ref_, Release()).Times(1);
+
+  const scoped_refptr<HasRef> refptr(&has_ref_);
+  Callback<int()> 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*()> 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);
+}
+
+TEST_F(BindTest, UniquePtrReceiver) {
+  std::unique_ptr<StrictMock<NoRef>> no_ref(new StrictMock<NoRef>);
+  EXPECT_CALL(*no_ref, VoidMethod0()).Times(1);
+  Bind(&NoRef::VoidMethod0, std::move(no_ref)).Run();
+}
+
+// Tests for 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.
+template <typename T>
+class BindMoveOnlyTypeTest : public ::testing::Test {
+};
+
+struct CustomDeleter {
+  void operator()(DeleteCounter* c) { delete c; }
+};
+
+using MoveOnlyTypesToTest =
+    ::testing::Types<std::unique_ptr<DeleteCounter>,
+                     std::unique_ptr<DeleteCounter>,
+                     std::unique_ptr<DeleteCounter, CustomDeleter>>;
+TYPED_TEST_CASE(BindMoveOnlyTypeTest, MoveOnlyTypesToTest);
+
+TYPED_TEST(BindMoveOnlyTypeTest, PassedToBoundCallback) {
+  int deletes = 0;
+
+  TypeParam ptr(new DeleteCounter(&deletes));
+  Callback<TypeParam()> callback = Bind(&PassThru<TypeParam>, Passed(&ptr));
+  EXPECT_FALSE(ptr.get());
+  EXPECT_EQ(0, deletes);
+
+  // If we never invoke the Callback, it retains ownership and deletes.
+  callback.Reset();
+  EXPECT_EQ(1, deletes);
+}
+
+TYPED_TEST(BindMoveOnlyTypeTest, PassedWithRvalue) {
+  int deletes = 0;
+  Callback<TypeParam()> callback = Bind(
+      &PassThru<TypeParam>, Passed(TypeParam(new DeleteCounter(&deletes))));
+  EXPECT_EQ(0, deletes);
+
+  // If we never invoke the Callback, it retains ownership and deletes.
+  callback.Reset();
+  EXPECT_EQ(1, deletes);
+}
+
+// Check that ownership can be transferred back out.
+TYPED_TEST(BindMoveOnlyTypeTest, ReturnMoveOnlyType) {
+  int deletes = 0;
+  DeleteCounter* counter = new DeleteCounter(&deletes);
+  Callback<TypeParam()> callback =
+      Bind(&PassThru<TypeParam>, Passed(TypeParam(counter)));
+  TypeParam 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);
+}
+
+TYPED_TEST(BindMoveOnlyTypeTest, UnboundForwarding) {
+  int deletes = 0;
+  TypeParam ptr(new DeleteCounter(&deletes));
+  // Test unbound argument forwarding.
+  Callback<TypeParam(TypeParam)> cb_unbound = Bind(&PassThru<TypeParam>);
+  cb_unbound.Run(std::move(ptr));
+  EXPECT_EQ(1, deletes);
+}
+
+void VerifyVector(const std::vector<std::unique_ptr<int>>& v) {
+  ASSERT_EQ(1u, v.size());
+  EXPECT_EQ(12345, *v[0]);
+}
+
+std::vector<std::unique_ptr<int>> AcceptAndReturnMoveOnlyVector(
+    std::vector<std::unique_ptr<int>> v) {
+  VerifyVector(v);
+  return v;
+}
+
+// Test that a vector containing move-only types can be used with Callback.
+TEST_F(BindTest, BindMoveOnlyVector) {
+  using MoveOnlyVector = std::vector<std::unique_ptr<int>>;
+
+  MoveOnlyVector v;
+  v.push_back(WrapUnique(new int(12345)));
+
+  // Early binding should work:
+  base::Callback<MoveOnlyVector()> bound_cb =
+      base::Bind(&AcceptAndReturnMoveOnlyVector, Passed(&v));
+  MoveOnlyVector intermediate_result = bound_cb.Run();
+  VerifyVector(intermediate_result);
+
+  // As should passing it as an argument to Run():
+  base::Callback<MoveOnlyVector(MoveOnlyVector)> unbound_cb =
+      base::Bind(&AcceptAndReturnMoveOnlyVector);
+  MoveOnlyVector final_result = unbound_cb.Run(std::move(intermediate_result));
+  VerifyVector(final_result);
+}
+
+// Argument copy-constructor usage for non-reference copy-only 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);
+  Bind(&VoidPolymorphic<CopyCounter>::Run, counter);
+  EXPECT_EQ(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  Bind(&VoidPolymorphic<CopyCounter>::Run, CopyCounter(&copies, &assigns));
+  EXPECT_EQ(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  Bind(&VoidPolymorphic<CopyCounter>::Run).Run(counter);
+  EXPECT_EQ(2, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(&copies, &assigns));
+  EXPECT_EQ(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  DerivedCopyMoveCounter derived(&copies, &assigns, nullptr, nullptr);
+  Bind(&VoidPolymorphic<CopyCounter>::Run).Run(CopyCounter(derived));
+  EXPECT_EQ(2, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  Bind(&VoidPolymorphic<CopyCounter>::Run)
+      .Run(CopyCounter(
+          DerivedCopyMoveCounter(&copies, &assigns, nullptr, nullptr)));
+  EXPECT_EQ(2, copies);
+  EXPECT_EQ(0, assigns);
+}
+
+// Argument move-constructor usage for move-only parameters.
+//   - Bound arguments passed by move are not copied.
+TEST_F(BindTest, ArgumentMoves) {
+  int move_constructs = 0;
+  int move_assigns = 0;
+
+  Bind(&VoidPolymorphic<const MoveCounter&>::Run,
+       MoveCounter(&move_constructs, &move_assigns));
+  EXPECT_EQ(1, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+
+  // TODO(tzik): Support binding move-only type into a non-reference parameter
+  // of a variant of Callback.
+
+  move_constructs = 0;
+  move_assigns = 0;
+  Bind(&VoidPolymorphic<MoveCounter>::Run)
+      .Run(MoveCounter(&move_constructs, &move_assigns));
+  EXPECT_EQ(1, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+
+  move_constructs = 0;
+  move_assigns = 0;
+  Bind(&VoidPolymorphic<MoveCounter>::Run)
+      .Run(MoveCounter(DerivedCopyMoveCounter(
+          nullptr, nullptr, &move_constructs, &move_assigns)));
+  EXPECT_EQ(2, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+}
+
+// Argument constructor usage for non-reference movable-copyable
+// parameters.
+//   - Bound arguments passed by move are not copied.
+//   - Forwarded arguments are only copied once.
+//   - Forwarded arguments with coercions are only copied once and moved once.
+TEST_F(BindTest, ArgumentCopiesAndMoves) {
+  int copies = 0;
+  int assigns = 0;
+  int move_constructs = 0;
+  int move_assigns = 0;
+
+  CopyMoveCounter counter(&copies, &assigns, &move_constructs, &move_assigns);
+  Bind(&VoidPolymorphic<CopyMoveCounter>::Run, counter);
+  EXPECT_EQ(1, copies);
+  EXPECT_EQ(0, assigns);
+  EXPECT_EQ(0, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+
+  copies = 0;
+  assigns = 0;
+  move_constructs = 0;
+  move_assigns = 0;
+  Bind(&VoidPolymorphic<CopyMoveCounter>::Run,
+       CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns));
+  EXPECT_EQ(0, copies);
+  EXPECT_EQ(0, assigns);
+  EXPECT_EQ(1, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+
+  copies = 0;
+  assigns = 0;
+  move_constructs = 0;
+  move_assigns = 0;
+  Bind(&VoidPolymorphic<CopyMoveCounter>::Run).Run(counter);
+  EXPECT_EQ(1, copies);
+  EXPECT_EQ(0, assigns);
+  EXPECT_EQ(1, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+
+  copies = 0;
+  assigns = 0;
+  move_constructs = 0;
+  move_assigns = 0;
+  Bind(&VoidPolymorphic<CopyMoveCounter>::Run)
+      .Run(CopyMoveCounter(&copies, &assigns, &move_constructs, &move_assigns));
+  EXPECT_EQ(0, copies);
+  EXPECT_EQ(0, assigns);
+  EXPECT_EQ(1, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+
+  DerivedCopyMoveCounter derived_counter(&copies, &assigns, &move_constructs,
+                                         &move_assigns);
+  copies = 0;
+  assigns = 0;
+  move_constructs = 0;
+  move_assigns = 0;
+  Bind(&VoidPolymorphic<CopyMoveCounter>::Run)
+      .Run(CopyMoveCounter(derived_counter));
+  EXPECT_EQ(1, copies);
+  EXPECT_EQ(0, assigns);
+  EXPECT_EQ(1, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+
+  copies = 0;
+  assigns = 0;
+  move_constructs = 0;
+  move_assigns = 0;
+  Bind(&VoidPolymorphic<CopyMoveCounter>::Run)
+      .Run(CopyMoveCounter(DerivedCopyMoveCounter(
+          &copies, &assigns, &move_constructs, &move_assigns)));
+  EXPECT_EQ(0, copies);
+  EXPECT_EQ(0, assigns);
+  EXPECT_EQ(2, move_constructs);
+  EXPECT_EQ(0, move_assigns);
+}
+
+TEST_F(BindTest, CapturelessLambda) {
+  EXPECT_FALSE(internal::IsConvertibleToRunType<void>::value);
+  EXPECT_FALSE(internal::IsConvertibleToRunType<int>::value);
+  EXPECT_FALSE(internal::IsConvertibleToRunType<void(*)()>::value);
+  EXPECT_FALSE(internal::IsConvertibleToRunType<void(NoRef::*)()>::value);
+
+  auto f = []() {};
+  EXPECT_TRUE(internal::IsConvertibleToRunType<decltype(f)>::value);
+
+  int i = 0;
+  auto g = [i]() {};
+  EXPECT_FALSE(internal::IsConvertibleToRunType<decltype(g)>::value);
+
+  auto h = [](int, double) { return 'k'; };
+  EXPECT_TRUE((std::is_same<
+      char(int, double),
+      internal::ExtractCallableRunType<decltype(h)>>::value));
+
+  EXPECT_EQ(42, Bind([] { return 42; }).Run());
+  EXPECT_EQ(42, Bind([](int i) { return i * 7; }, 6).Run());
+
+  int x = 1;
+  base::Callback<void(int)> cb =
+      Bind([](int* x, int i) { *x *= i; }, Unretained(&x));
+  cb.Run(6);
+  EXPECT_EQ(6, x);
+  cb.Run(7);
+  EXPECT_EQ(42, x);
+}
+
+// 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()> fastcall_cb = Bind(&FastCallFunc, 1);
+  EXPECT_EQ(1, fastcall_cb.Run());
+
+  Callback<int()> 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/libchrome/base/bit_cast.h b/libchrome/base/bit_cast.h
new file mode 100644
index 0000000..c9514bc
--- /dev/null
+++ b/libchrome/base/bit_cast.h
@@ -0,0 +1,100 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIT_CAST_H_
+#define BASE_BIT_CAST_H_
+
+#include <string.h>
+#include <type_traits>
+
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+
+// 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_t>(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
+// the ISO C++98 specification, section 3.10 ("basic.lval"), paragraph 15.
+// (This did not substantially change in C++11.)  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 this paragraph is to allow optimizing compilers to assume that
+// expressions with different types refer to different memory.  Compilers are
+// known to take 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, compilers replace
+// calls to memcpy() with inline object code when the size argument is a
+// compile-time constant.  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.
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+  static_assert(sizeof(Dest) == sizeof(Source),
+                "bit_cast requires source and destination to be the same size");
+
+#if (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) || \
+     (defined(__clang__) && defined(_LIBCPP_VERSION)))
+  // GCC 5.1 contains the first libstdc++ with is_trivially_copyable.
+  // Assume libc++ Just Works: is_trivially_copyable added on May 13th 2011.
+  // However, with libc++ when GCC is the compiler the trait is buggy, see
+  // crbug.com/607158, so fall back to the less strict variant for non-clang.
+  static_assert(std::is_trivially_copyable<Dest>::value,
+                "non-trivially-copyable bit_cast is undefined");
+  static_assert(std::is_trivially_copyable<Source>::value,
+                "non-trivially-copyable bit_cast is undefined");
+#elif HAS_FEATURE(is_trivially_copyable)
+  // The compiler supports an equivalent intrinsic.
+  static_assert(__is_trivially_copyable(Dest),
+                "non-trivially-copyable bit_cast is undefined");
+  static_assert(__is_trivially_copyable(Source),
+                "non-trivially-copyable bit_cast is undefined");
+#elif COMPILER_GCC
+  // Fallback to compiler intrinsic on GCC and clang (which pretends to be
+  // GCC). This isn't quite the same as is_trivially_copyable but it'll do for
+  // our purpose.
+  static_assert(__has_trivial_copy(Dest),
+                "non-trivially-copyable bit_cast is undefined");
+  static_assert(__has_trivial_copy(Source),
+                "non-trivially-copyable bit_cast is undefined");
+#else
+  // Do nothing, let the bots handle it.
+#endif
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+#endif  // BASE_BIT_CAST_H_
diff --git a/libchrome/base/bits.h b/libchrome/base/bits.h
new file mode 100644
index 0000000..a3a59d1
--- /dev/null
+++ b/libchrome/base/bits.h
@@ -0,0 +1,55 @@
+// 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 <stddef.h>
+#include <stdint.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_t n) {
+  if (n == 0)
+    return -1;
+  int log = 0;
+  uint32_t value = n;
+  for (int i = 4; i >= 0; --i) {
+    int shift = (1 << i);
+    uint32_t 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_t 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);
+  }
+}
+
+// Round up |size| to a multiple of alignment, which must be a power of two.
+inline size_t Align(size_t size, size_t alignment) {
+  DCHECK_EQ(alignment & (alignment - 1), 0u);
+  return (size + alignment - 1) & ~(alignment - 1);
+}
+
+}  // namespace bits
+}  // namespace base
+
+#endif  // BASE_BITS_H_
diff --git a/libchrome/base/bits_unittest.cc b/libchrome/base/bits_unittest.cc
new file mode 100644
index 0000000..4f5b6ea
--- /dev/null
+++ b/libchrome/base/bits_unittest.cc
@@ -0,0 +1,65 @@
+// 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 <stddef.h>
+
+#include <limits>
+
+#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));
+}
+
+TEST(BitsTest, Align) {
+  const size_t kSizeTMax = std::numeric_limits<size_t>::max();
+  EXPECT_EQ(0ul, Align(0, 4));
+  EXPECT_EQ(4ul, Align(1, 4));
+  EXPECT_EQ(4096ul, Align(1, 4096));
+  EXPECT_EQ(4096ul, Align(4096, 4096));
+  EXPECT_EQ(4096ul, Align(4095, 4096));
+  EXPECT_EQ(8192ul, Align(4097, 4096));
+  EXPECT_EQ(kSizeTMax - 31, Align(kSizeTMax - 62, 32));
+  EXPECT_EQ(kSizeTMax / 2 + 1, Align(1, kSizeTMax / 2 + 1));
+}
+
+}  // namespace bits
+}  // namespace base
diff --git a/libchrome/base/build_time.cc b/libchrome/base/build_time.cc
new file mode 100644
index 0000000..866840d
--- /dev/null
+++ b/libchrome/base/build_time.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/build_time.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+
+#ifdef __ANDROID__
+#include <cutils/properties.h>
+#endif
+
+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(__ANDROID__)
+  char kDateTime[PROPERTY_VALUE_MAX];
+  property_get("ro.build.date", kDateTime, "Sep 02 2008 08:00:00 PST");
+#elif 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/libchrome/base/build_time.h b/libchrome/base/build_time.h
new file mode 100644
index 0000000..83c9875
--- /dev/null
+++ b/libchrome/base/build_time.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_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,
+// rounded down to 5:00:00am at the start of the day in UTC.
+//
+// This uses a generated file, which doesn't trigger a rebuild when the time
+// changes. It will, however, be updated whenever //build/util/LASTCHANGE
+// changes.
+//
+// This value should only be considered accurate to within a day.
+// It will always be in the past.
+//
+// Note: If the build is not official (i.e. is_official_build = false)
+// this time will be set to 5:00:00am on the most recent first Sunday
+// of a month.
+Time BASE_EXPORT GetBuildTime();
+
+}  // namespace base
+
+#endif  // BASE_BUILD_TIME_H_
diff --git a/libchrome/base/build_time_unittest.cc b/libchrome/base/build_time_unittest.cc
new file mode 100644
index 0000000..64886b4
--- /dev/null
+++ b/libchrome/base/build_time_unittest.cc
@@ -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.
+
+#include "base/build_time.h"
+#if !defined(DONT_EMBED_BUILD_METADATA)
+#include "base/generated_build_date.h"
+#endif
+#include "base/time/time.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(BuildTime, DateLooksValid) {
+#if !defined(DONT_EMBED_BUILD_METADATA)
+  char build_date[] = BUILD_DATE;
+#else
+  char build_date[] = "Sep 02 2008 05:00:00";
+#endif
+
+  EXPECT_EQ(20u, strlen(build_date));
+  EXPECT_EQ(' ', build_date[3]);
+  EXPECT_EQ(' ', build_date[6]);
+  EXPECT_EQ(' ', build_date[11]);
+  EXPECT_EQ('0', build_date[12]);
+  EXPECT_EQ('5', build_date[13]);
+  EXPECT_EQ(':', build_date[14]);
+  EXPECT_EQ('0', build_date[15]);
+  EXPECT_EQ('0', build_date[16]);
+  EXPECT_EQ(':', build_date[17]);
+  EXPECT_EQ('0', build_date[18]);
+  EXPECT_EQ('0', build_date[19]);
+}
+
+TEST(BuildTime, InThePast) {
+  EXPECT_LT(base::GetBuildTime(), base::Time::Now());
+  EXPECT_LT(base::GetBuildTime(), base::Time::NowFromSystemTime());
+}
+
+#if !defined(DONT_EMBED_BUILD_METADATA)
+TEST(BuildTime, NotTooFar) {
+  // BuildTime must be less than 45 days old.
+  base::Time cutoff(base::Time::Now() - base::TimeDelta::FromDays(45));
+  EXPECT_GT(base::GetBuildTime(), cutoff);
+}
+#endif
diff --git a/libchrome/base/callback.h b/libchrome/base/callback.h
new file mode 100644
index 0000000..e087c73
--- /dev/null
+++ b/libchrome/base/callback.h
@@ -0,0 +1,395 @@
+// Copyright (c) 2012 The Chromium Authors. All 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"
+
+// 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()>)
+// 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()> 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()> 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()> cb = base::Bind(&MyFunc, 23, "hello world");
+//   cb.Run();
+//
+//   A callback with no unbound input parameters (base::Callback<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()> 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(std::unique_ptr<Foo> arg) {}
+//   std::unique_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.
+//
+// If you are thinking of forward declaring Callback in your own header file,
+// please include "base/callback_forward.h" instead.
+
+namespace base {
+
+template <typename R, typename... Args, internal::CopyMode copy_mode>
+class Callback<R(Args...), copy_mode>
+    : public internal::CallbackBase<copy_mode> {
+ private:
+  using PolymorphicInvoke = R (*)(internal::BindStateBase*, Args&&...);
+
+ public:
+  // MSVC 2013 doesn't support Type Alias of function types.
+  // Revisit this after we update it to newer version.
+  typedef R RunType(Args...);
+
+  Callback() : internal::CallbackBase<copy_mode>(nullptr) {}
+
+  Callback(internal::BindStateBase* bind_state,
+           PolymorphicInvoke invoke_func)
+      : internal::CallbackBase<copy_mode>(bind_state) {
+    using InvokeFuncStorage =
+        typename internal::CallbackBase<copy_mode>::InvokeFuncStorage;
+    this->polymorphic_invoke_ =
+        reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return this->EqualsInternal(other);
+  }
+
+  // Run() makes an extra copy compared to directly calling the bound function
+  // if an argument is passed-by-value and is copyable-but-not-movable:
+  // i.e. below copies CopyableNonMovableType twice.
+  //   void F(CopyableNonMovableType) {}
+  //   Bind(&F).Run(CopyableNonMovableType());
+  //
+  // We can not fully apply Perfect Forwarding idiom to the callchain from
+  // Callback::Run() to the target function. Perfect Forwarding requires
+  // knowing how the caller will pass the arguments. However, the signature of
+  // InvokerType::Run() needs to be fixed in the callback constructor, so Run()
+  // cannot template its arguments based on how it's called.
+  R Run(Args... args) const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke_);
+    return f(this->bind_state_.get(), std::forward<Args>(args)...);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_H_
diff --git a/libchrome/base/callback_forward.h b/libchrome/base/callback_forward.h
new file mode 100644
index 0000000..8b9b89c
--- /dev/null
+++ b/libchrome/base/callback_forward.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_CALLBACK_FORWARD_H_
+#define BASE_CALLBACK_FORWARD_H_
+
+namespace base {
+namespace internal {
+
+// CopyMode is used to control the copyablity of a Callback.
+// MoveOnly indicates the Callback is not copyable but movable, and Copyable
+// indicates it is copyable and movable.
+enum class CopyMode {
+  MoveOnly, Copyable,
+};
+
+}  // namespace internal
+
+template <typename Signature,
+          internal::CopyMode copy_mode = internal::CopyMode::Copyable>
+class Callback;
+
+// Syntactic sugar to make Callback<void()> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+using Closure = Callback<void()>;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_FORWARD_H_
diff --git a/libchrome/base/callback_helpers.cc b/libchrome/base/callback_helpers.cc
new file mode 100644
index 0000000..838e6c8
--- /dev/null
+++ b/libchrome/base/callback_helpers.cc
@@ -0,0 +1,46 @@
+// 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();
+}
+
+ScopedClosureRunner::ScopedClosureRunner(ScopedClosureRunner&& other)
+    : closure_(other.Release()) {}
+
+ScopedClosureRunner& ScopedClosureRunner::operator=(
+    ScopedClosureRunner&& other) {
+  ReplaceClosure(other.Release());
+  return *this;
+}
+
+void ScopedClosureRunner::RunAndReset() {
+  Closure old_closure = Release();
+  if (!old_closure.is_null())
+    old_closure.Run();
+}
+
+void ScopedClosureRunner::ReplaceClosure(const Closure& closure) {
+  closure_ = closure;
+}
+
+Closure ScopedClosureRunner::Release() {
+  Closure result = closure_;
+  closure_.Reset();
+  return result;
+}
+
+}  // namespace base
diff --git a/libchrome/base/callback_helpers.h b/libchrome/base/callback_helpers.h
new file mode 100644
index 0000000..782371f
--- /dev/null
+++ b/libchrome/base/callback_helpers.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.
+
+// 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/callback.h"
+#include "base/compiler_specific.h"
+#include "base/macros.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 std::unique_ptr<> for Closures. It ensures
+// that the Closure is executed no matter how the current scope exits.
+class BASE_EXPORT ScopedClosureRunner {
+ public:
+  ScopedClosureRunner();
+  explicit ScopedClosureRunner(const Closure& closure);
+  ~ScopedClosureRunner();
+
+  ScopedClosureRunner(ScopedClosureRunner&& other);
+
+  // Releases the current closure if it's set and replaces it with the closure
+  // from |other|.
+  ScopedClosureRunner& operator=(ScopedClosureRunner&& other);
+
+  // Calls the current closure and resets it, so it wont be called again.
+  void RunAndReset();
+
+  // Replaces closure with the new one releasing the old one without calling it.
+  void ReplaceClosure(const Closure& closure);
+
+  // Releases the Closure without calling.
+  Closure Release() WARN_UNUSED_RESULT;
+
+ private:
+  Closure closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_HELPERS_H_
diff --git a/libchrome/base/callback_helpers_unittest.cc b/libchrome/base/callback_helpers_unittest.cc
new file mode 100644
index 0000000..8283996
--- /dev/null
+++ b/libchrome/base/callback_helpers_unittest.cc
@@ -0,0 +1,94 @@
+// 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(CallbackHelpersTest, TestScopedClosureRunnerExitScope) {
+  int run_count = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(CallbackHelpersTest, 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(CallbackHelpersTest, TestScopedClosureRunnerReplaceClosure) {
+  int run_count_1 = 0;
+  int run_count_2 = 0;
+  {
+    base::ScopedClosureRunner runner;
+    runner.ReplaceClosure(base::Bind(&Increment, &run_count_1));
+    runner.ReplaceClosure(base::Bind(&Increment, &run_count_2));
+    EXPECT_EQ(0, run_count_1);
+    EXPECT_EQ(0, run_count_2);
+  }
+  EXPECT_EQ(0, run_count_1);
+  EXPECT_EQ(1, run_count_2);
+}
+
+TEST(CallbackHelpersTest, TestScopedClosureRunnerRunAndReset) {
+  int run_count_3 = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_3));
+    EXPECT_EQ(0, run_count_3);
+    runner.RunAndReset();
+    EXPECT_EQ(1, run_count_3);
+  }
+  EXPECT_EQ(1, run_count_3);
+}
+
+TEST(CallbackHelpersTest, TestScopedClosureRunnerMoveConstructor) {
+  int run_count = 0;
+  {
+    std::unique_ptr<base::ScopedClosureRunner> runner(
+        new base::ScopedClosureRunner(base::Bind(&Increment, &run_count)));
+    base::ScopedClosureRunner runner2(std::move(*runner));
+    runner.reset();
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(CallbackHelpersTest, TestScopedClosureRunnerMoveAssignment) {
+  int run_count_1 = 0;
+  int run_count_2 = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_1));
+    {
+      base::ScopedClosureRunner runner2(base::Bind(&Increment, &run_count_2));
+      runner = std::move(runner2);
+      EXPECT_EQ(0, run_count_1);
+      EXPECT_EQ(0, run_count_2);
+    }
+    EXPECT_EQ(0, run_count_1);
+    EXPECT_EQ(0, run_count_2);
+  }
+  EXPECT_EQ(0, run_count_1);
+  EXPECT_EQ(1, run_count_2);
+}
+
+}  // namespace
diff --git a/libchrome/base/callback_internal.cc b/libchrome/base/callback_internal.cc
new file mode 100644
index 0000000..4c8ccae
--- /dev/null
+++ b/libchrome/base/callback_internal.cc
@@ -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/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<CopyMode::MoveOnly>::CallbackBase(CallbackBase&& c)
+    : bind_state_(std::move(c.bind_state_)),
+      polymorphic_invoke_(c.polymorphic_invoke_) {
+  c.polymorphic_invoke_ = nullptr;
+}
+
+CallbackBase<CopyMode::MoveOnly>&
+CallbackBase<CopyMode::MoveOnly>::operator=(CallbackBase&& c) {
+  bind_state_ = std::move(c.bind_state_);
+  polymorphic_invoke_ = c.polymorphic_invoke_;
+  c.polymorphic_invoke_ = nullptr;
+  return *this;
+}
+
+void CallbackBase<CopyMode::MoveOnly>::Reset() {
+  polymorphic_invoke_ = nullptr;
+  // 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_ = nullptr;
+}
+
+bool CallbackBase<CopyMode::MoveOnly>::EqualsInternal(
+    const CallbackBase& other) const {
+  return bind_state_.get() == other.bind_state_.get() &&
+         polymorphic_invoke_ == other.polymorphic_invoke_;
+}
+
+CallbackBase<CopyMode::MoveOnly>::CallbackBase(
+    BindStateBase* bind_state)
+    : bind_state_(bind_state) {
+  DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
+}
+
+CallbackBase<CopyMode::MoveOnly>::~CallbackBase() {}
+
+CallbackBase<CopyMode::Copyable>::CallbackBase(
+    const CallbackBase& c)
+    : CallbackBase<CopyMode::MoveOnly>(nullptr) {
+  bind_state_ = c.bind_state_;
+  polymorphic_invoke_ = c.polymorphic_invoke_;
+}
+
+CallbackBase<CopyMode::Copyable>::CallbackBase(CallbackBase&& c)
+    : CallbackBase<CopyMode::MoveOnly>(std::move(c)) {}
+
+CallbackBase<CopyMode::Copyable>&
+CallbackBase<CopyMode::Copyable>::operator=(const CallbackBase& c) {
+  bind_state_ = c.bind_state_;
+  polymorphic_invoke_ = c.polymorphic_invoke_;
+  return *this;
+}
+
+CallbackBase<CopyMode::Copyable>&
+CallbackBase<CopyMode::Copyable>::operator=(CallbackBase&& c) {
+  *static_cast<CallbackBase<CopyMode::MoveOnly>*>(this) = std::move(c);
+  return *this;
+}
+
+template class CallbackBase<CopyMode::MoveOnly>;
+template class CallbackBase<CopyMode::Copyable>;
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/callback_internal.h b/libchrome/base/callback_internal.h
new file mode 100644
index 0000000..0fe0b2d
--- /dev/null
+++ b/libchrome/base/callback_internal.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.
+
+// 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 "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+namespace internal {
+template <CopyMode copy_mode>
+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>;
+  template <CopyMode copy_mode>
+  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.
+// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
+// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
+template <>
+class BASE_EXPORT CallbackBase<CopyMode::MoveOnly> {
+ public:
+  CallbackBase(CallbackBase&& c);
+  CallbackBase& operator=(CallbackBase&& c);
+
+  // Returns true if Callback is null (doesn't refer to anything).
+  bool is_null() const { return bind_state_.get() == NULL; }
+  explicit operator bool() const { return !is_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.
+  using InvokeFuncStorage = void(*)();
+
+  // Returns true if this callback equals |other|. |other| may be null.
+  bool EqualsInternal(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_ = nullptr;
+};
+
+// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
+template <>
+class BASE_EXPORT CallbackBase<CopyMode::Copyable>
+    : public CallbackBase<CopyMode::MoveOnly> {
+ public:
+  CallbackBase(const CallbackBase& c);
+  CallbackBase(CallbackBase&& c);
+  CallbackBase& operator=(const CallbackBase& c);
+  CallbackBase& operator=(CallbackBase&& c);
+ protected:
+  explicit CallbackBase(BindStateBase* bind_state)
+      : CallbackBase<CopyMode::MoveOnly>(bind_state) {}
+  ~CallbackBase() {}
+};
+
+extern template class CallbackBase<CopyMode::MoveOnly>;
+extern template class CallbackBase<CopyMode::Copyable>;
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_CALLBACK_INTERNAL_H_
diff --git a/libchrome/base/callback_list.h b/libchrome/base/callback_list.h
new file mode 100644
index 0000000..7ab79dd
--- /dev/null
+++ b/libchrome/base/callback_list.h
@@ -0,0 +1,229 @@
+// 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 <memory>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.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;
+//
+//   std::unique_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.
+//   }
+//
+//   std::unique_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.
+  std::unique_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
+    DCHECK(!cb.is_null());
+    return std::unique_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() {}
+
+  template <typename... RunArgs>
+  void Notify(RunArgs&&... 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/libchrome/base/callback_list_unittest.cc b/libchrome/base/callback_list_unittest.cc
new file mode 100644
index 0000000..62081e9
--- /dev/null
+++ b/libchrome/base/callback_list_unittest.cc
@@ -0,0 +1,339 @@
+// 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 <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/macros.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(
+      std::unique_ptr<CallbackList<void(void)>::Subscription> sub) {
+    removal_subscription_ = std::move(sub);
+  }
+
+  int total() const { return total_; }
+
+ private:
+  int total_;
+  std::unique_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_;
+  std::unique_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);
+};
+
+class Counter {
+ public:
+  Counter() : value_(0) {}
+
+  void Increment() { value_++; }
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+  DISALLOW_COPY_AND_ASSIGN(Counter);
+};
+
+// Sanity check that we can instantiate a CallbackList for each arity.
+TEST(CallbackListTest, ArityTest) {
+  Summer s;
+
+  CallbackList<void(int)> c1;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+
+  std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+  std::unique_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();
+
+  std::unique_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);
+
+  std::unique_ptr<CallbackList<void(int)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
+  std::unique_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();
+
+  std::unique_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;
+
+  std::unique_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
+      cb_reg.Add(
+          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
+  std::unique_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
+      cb_reg.Add(
+          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
+  std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+  std::unique_ptr<CallbackList<void(void)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+
+  // |remover_1| will remove itself.
+  remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
+  // |remover_2| will remove a.
+  remover_2.SetSubscriptionToRemove(std::move(a_subscription));
+
+  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;
+  std::unique_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Adder::AddCallback, Unretained(&a)));
+  std::unique_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();
+}
+
+TEST(CallbackList, RemovalCallback) {
+  Counter remove_count;
+  CallbackList<void(void)> cb_reg;
+  cb_reg.set_removal_callback(
+      Bind(&Counter::Increment, Unretained(&remove_count)));
+
+  std::unique_ptr<CallbackList<void(void)>::Subscription> subscription =
+      cb_reg.Add(Bind(&DoNothing));
+
+  // Removing a subscription outside of iteration signals the callback.
+  EXPECT_EQ(0, remove_count.value());
+  subscription.reset();
+  EXPECT_EQ(1, remove_count.value());
+
+  // Configure two subscriptions to remove themselves.
+  Remover remover_1, remover_2;
+  std::unique_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
+      cb_reg.Add(
+          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_1)));
+  std::unique_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
+      cb_reg.Add(
+          Bind(&Remover::IncrementTotalAndRemove, Unretained(&remover_2)));
+  remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
+  remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
+
+  // The callback should be signaled exactly once.
+  EXPECT_EQ(1, remove_count.value());
+  cb_reg.Notify();
+  EXPECT_EQ(2, remove_count.value());
+  EXPECT_TRUE(cb_reg.empty());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/libchrome/base/callback_unittest.cc b/libchrome/base/callback_unittest.cc
new file mode 100644
index 0000000..ce453a1
--- /dev/null
+++ b/libchrome/base/callback_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/callback.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+void NopInvokeFunc(internal::BindStateBase*) {}
+
+// 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.
+struct FakeBindState1 : internal::BindStateBase {
+  FakeBindState1() : BindStateBase(&Destroy) {}
+ private:
+  ~FakeBindState1() {}
+  static void Destroy(internal::BindStateBase* self) {
+    delete static_cast<FakeBindState1*>(self);
+  }
+};
+
+struct FakeBindState2 : internal::BindStateBase {
+  FakeBindState2() : BindStateBase(&Destroy) {}
+ private:
+  ~FakeBindState2() {}
+  static void Destroy(internal::BindStateBase* self) {
+    delete static_cast<FakeBindState2*>(self);
+  }
+};
+
+namespace {
+
+class CallbackTest : public ::testing::Test {
+ public:
+  CallbackTest()
+      : callback_a_(new FakeBindState1(), &NopInvokeFunc),
+        callback_b_(new FakeBindState2(), &NopInvokeFunc) {
+  }
+
+  ~CallbackTest() override {}
+
+ protected:
+  Callback<void()> callback_a_;
+  const Callback<void()> callback_b_;  // Ensure APIs work with const.
+  Callback<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()> 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()> callback_c(new FakeBindState1(), &NopInvokeFunc);
+  Callback<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()> 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/libchrome/base/cancelable_callback.h b/libchrome/base/cancelable_callback.h
new file mode 100644
index 0000000..0034fdd
--- /dev/null
+++ b/libchrome/base/cancelable_callback.h
@@ -0,0 +1,134 @@
+// 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 <utility>
+
+#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/macros.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(std::forward<A>(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/libchrome/base/cancelable_callback_unittest.cc b/libchrome/base/cancelable_callback_unittest.cc
new file mode 100644
index 0000000..23b6c1c
--- /dev/null
+++ b/libchrome/base/cancelable_callback_unittest.cc
@@ -0,0 +1,205 @@
+// 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 <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/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) {}
+
+void OnMoveOnlyReceived(int* value, std::unique_ptr<int> result) {
+  *value = *result;
+}
+
+// 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);
+}
+
+// CancelableCallback can be used with move-only types.
+TEST(CancelableCallbackTest, MoveOnlyType) {
+  const int kExpectedResult = 42;
+
+  int result = 0;
+  CancelableCallback<void(std::unique_ptr<int>)> cb(
+      base::Bind(&OnMoveOnlyReceived, base::Unretained(&result)));
+  cb.callback().Run(base::WrapUnique(new int(kExpectedResult)));
+
+  EXPECT_EQ(kExpectedResult, result);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/libchrome/base/command_line.cc b/libchrome/base/command_line.cc
new file mode 100644
index 0000000..099bb18
--- /dev/null
+++ b/libchrome/base/command_line.cc
@@ -0,0 +1,493 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/files/file_path.h"
+#include "base/logging.h"
+#include "base/macros.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];
+#if defined(OS_WIN)
+    TrimWhitespace(arg, TRIM_ALL, &arg);
+#else
+    TrimWhitespaceASCII(arg, TRIM_ALL, &arg);
+#endif
+
+    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) : 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;
+}
+
+// static
+void CommandLine::InitUsingArgvForTesting(int argc, const char* const* argv) {
+  DCHECK(!current_process_commandline_);
+  current_process_commandline_ = new CommandLine(NO_PROGRAM);
+  // On Windows we need to convert the command line arguments to string16.
+  base::CommandLine::StringVector argv_vector;
+  for (int i = 0; i < argc; ++i)
+    argv_vector.push_back(UTF8ToUTF16(argv[i]));
+  current_process_commandline_->InitFromArgv(argv_vector);
+}
+#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) {
+#if defined(OS_WIN)
+  TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
+#else
+  TrimWhitespaceASCII(program.value(), TRIM_ALL, &argv_[0]);
+#endif
+}
+
+bool CommandLine::HasSwitch(const base::StringPiece& switch_string) const {
+  DCHECK_EQ(ToLowerASCII(switch_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(ToLowerASCII(switch_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 = ToLowerASCII(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, FilePath::StringType(1, ' '), base::TRIM_WHITESPACE,
+      base::SPLIT_WANT_ALL);
+  // 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 {
+#if !defined(OS_WIN)
+  (void)quote_placeholders;  // Avoid an unused warning.
+#endif
+  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/libchrome/base/command_line.h b/libchrome/base/command_line.h
new file mode 100644
index 0000000..3d29f8f
--- /dev/null
+++ b/libchrome/base/command_line.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.
+
+// 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.
+  using StringType = string16;
+#elif defined(OS_POSIX)
+  using StringType = std::string;
+#endif
+
+  using CharType = StringType::value_type;
+  using StringVector = std::vector<StringType>;
+  using SwitchMap = std::map<std::string, StringType>;
+  using StringPieceSwitchMap = std::map<StringPiece, const StringType*>;
+
+  // 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();
+
+  // Normally when the CommandLine singleton is initialized it gets the command
+  // line via the GetCommandLineW API and then uses the shell32 API
+  // CommandLineToArgvW to parse the command line and convert it back to
+  // argc and argv. Tests who don't want this dependency on shell32 and need
+  // to honor the arguments passed in should use this function.
+  static void InitUsingArgvForTesting(int argc, const char* const* argv);
+#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.
+  // Do not call this in tests. Use base::test::ScopedCommandLine instead.
+  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 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 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 StringPiece& switch_string) const;
+  FilePath GetSwitchValuePath(const StringPiece& switch_string) const;
+  StringType GetSwitchValueNative(const 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 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/libchrome/base/command_line_unittest.cc b/libchrome/base/command_line_unittest.cc
new file mode 100644
index 0000000..bcfc6c5
--- /dev/null
+++ b/libchrome/base/command_line_unittest.cc
@@ -0,0 +1,409 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.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) {
+  // Call Init without checking output once so we know it's been called
+  // whether or not the test runner does so.
+  CommandLine::Init(0, NULL);
+  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) {
+  std::unique_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/libchrome/base/compiler_specific.h b/libchrome/base/compiler_specific.h
new file mode 100644
index 0000000..c2a02de
--- /dev/null
+++ b/libchrome/base/compiler_specific.h
@@ -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.
+
+#ifndef BASE_COMPILER_SPECIFIC_H_
+#define BASE_COMPILER_SPECIFIC_H_
+
+#include "build/build_config.h"
+
+#if defined(ANDROID)
+// Prefer Android's libbase definitions to our own.
+#include <android-base/macros.h>
+#endif  // defined(ANDROID)
+
+#if defined(COMPILER_MSVC)
+
+// For _Printf_format_string_.
+#include <sal.h>
+
+// 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 _Printf_format_string_
+#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
+
+
+// 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) || defined(__clang__)
+#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_t)  // 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/macros.h.
+#undef WARN_UNUSED_RESULT
+#if defined(COMPILER_GCC) || defined(__clang__)
+#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)
+
+// Compiler feature-detection.
+// clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
+#if defined(__has_feature)
+#define HAS_FEATURE(FEATURE) __has_feature(FEATURE)
+#else
+#define HAS_FEATURE(FEATURE) 0
+#endif
+
+#endif  // BASE_COMPILER_SPECIFIC_H_
diff --git a/libchrome/base/containers/adapters.h b/libchrome/base/containers/adapters.h
new file mode 100644
index 0000000..fa671b4
--- /dev/null
+++ b/libchrome/base/containers/adapters.h
@@ -0,0 +1,73 @@
+// 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 <stddef.h>
+
+#include <iterator>
+
+#include "base/macros.h"
+
+namespace base {
+
+namespace internal {
+
+// Internal adapter class for implementing base::Reversed.
+template <typename T>
+class ReversedAdapter {
+ public:
+  using Iterator = decltype(static_cast<T*>(nullptr)->rbegin());
+
+  explicit ReversedAdapter(T& t) : t_(t) {}
+  ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+  // TODO(mdempsky): Once we can use C++14 library features, use std::rbegin
+  // and std::rend instead, so we can remove the specialization below.
+  Iterator begin() const { return t_.rbegin(); }
+  Iterator end() const { return t_.rend(); }
+
+ private:
+  T& t_;
+
+  DISALLOW_ASSIGN(ReversedAdapter);
+};
+
+template <typename T, size_t N>
+class ReversedAdapter<T[N]> {
+ public:
+  using Iterator = std::reverse_iterator<T*>;
+
+  explicit ReversedAdapter(T (&t)[N]) : t_(t) {}
+  ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+  Iterator begin() const { return Iterator(&t_[N]); }
+  Iterator end() const { return Iterator(&t_[0]); }
+
+ private:
+  T (&t_)[N];
+
+  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/libchrome/base/containers/hash_tables.h b/libchrome/base/containers/hash_tables.h
new file mode 100644
index 0000000..8da7b67
--- /dev/null
+++ b/libchrome/base/containers/hash_tables.h
@@ -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.
+
+#ifndef BASE_CONTAINERS_HASH_TABLES_H_
+#define BASE_CONTAINERS_HASH_TABLES_H_
+
+#include <cstddef>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+
+#include "base/hash.h"
+
+// This header file is deprecated. Use the corresponding C++11 type
+// instead. https://crbug.com/576864
+
+// Use a custom hasher instead.
+#define BASE_HASH_NAMESPACE base_hash
+
+namespace BASE_HASH_NAMESPACE {
+
+// A separate hasher which, by default, forwards to std::hash. This is so legacy
+// uses of BASE_HASH_NAMESPACE with base::hash_map do not interfere with
+// std::hash mid-transition.
+template<typename T>
+struct hash {
+  std::size_t operator()(const T& value) const { return std::hash<T>()(value); }
+};
+
+// Use base::IntPairHash from base/hash.h as a custom hasher instead.
+template <typename Type1, typename Type2>
+struct hash<std::pair<Type1, Type2>> {
+  std::size_t operator()(std::pair<Type1, Type2> value) const {
+    return base::HashInts(value.first, value.second);
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+namespace base {
+
+// Use std::unordered_map instead.
+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 = std::unordered_map<Key, T, Hash, Pred, Alloc>;
+
+// Use std::unordered_multimap instead.
+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 = std::unordered_multimap<Key, T, Hash, Pred, Alloc>;
+
+// Use std::unordered_multiset instead.
+template <class Key,
+          class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+          class Pred = std::equal_to<Key>,
+          class Alloc = std::allocator<Key>>
+using hash_multiset = std::unordered_multiset<Key, Hash, Pred, Alloc>;
+
+// Use std::unordered_set instead.
+template <class Key,
+          class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+          class Pred = std::equal_to<Key>,
+          class Alloc = std::allocator<Key>>
+using hash_set = std::unordered_set<Key, Hash, Pred, Alloc>;
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_HASH_TABLES_H_
diff --git a/libchrome/base/containers/linked_list.h b/libchrome/base/containers/linked_list.h
new file mode 100644
index 0000000..41461ff
--- /dev/null
+++ b/libchrome/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/libchrome/base/containers/mru_cache.h b/libchrome/base/containers/mru_cache.h
new file mode 100644
index 0000000..6c1d626
--- /dev/null
+++ b/libchrome/base/containers/mru_cache.h
@@ -0,0 +1,256 @@
+// 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 <stddef.h>
+
+#include <algorithm>
+#include <functional>
+#include <list>
+#include <map>
+#include <unordered_map>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.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, class CompareType>
+struct MRUCacheStandardMap {
+  typedef std::map<KeyType, ValueType, CompareType> Type;
+};
+
+// Base class for the MRU cache specializations defined below.
+template <class KeyType,
+          class PayloadType,
+          class HashOrCompareType,
+          template <typename, 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,
+                           HashOrCompareType>::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) {}
+
+  virtual ~MRUCacheBase() {}
+
+  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 forwarded.
+  template <typename Payload>
+  iterator Put(const KeyType& key, Payload&& 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. 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, std::forward<Payload>(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;
+  }
+
+  // Exchanges the contents of |this| by the contents of the |other|.
+  void Swap(MRUCacheBase& other) {
+    ordering_.swap(other.ordering_);
+    index_.swap(other.index_);
+    std::swap(max_size_, other.max_size_);
+  }
+
+  // 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) {
+    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() {
+    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_;
+
+  DISALLOW_COPY_AND_ASSIGN(MRUCacheBase);
+};
+
+// MRUCache --------------------------------------------------------------------
+
+// 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, std::less<KeyType>> {
+ private:
+  using ParentType = MRUCacheBase<KeyType, PayloadType, std::less<KeyType>>;
+
+ 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);
+};
+
+// HashingMRUCache ------------------------------------------------------------
+
+template <class KeyType, class ValueType, class HashType>
+struct MRUCacheHashMap {
+  typedef std::unordered_map<KeyType, ValueType, HashType> Type;
+};
+
+// This class is similar to MRUCache, except that it uses std::unordered_map as
+// the map type instead of std::map. Note that your KeyType must be hashable to
+// use this cache or you need to provide a hashing class.
+template <class KeyType, class PayloadType, class HashType = std::hash<KeyType>>
+class HashingMRUCache
+    : public MRUCacheBase<KeyType, PayloadType, HashType, MRUCacheHashMap> {
+ private:
+  using ParentType =
+      MRUCacheBase<KeyType, PayloadType, HashType, MRUCacheHashMap>;
+
+ 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/libchrome/base/containers/scoped_ptr_hash_map.h b/libchrome/base/containers/scoped_ptr_hash_map.h
new file mode 100644
index 0000000..f513f06
--- /dev/null
+++ b/libchrome/base/containers/scoped_ptr_hash_map.h
@@ -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.
+
+#ifndef BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+#define BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+// Deprecated. Use std::unordered_map instead. https://crbug.com/579229
+//
+// This type acts like a hash_map<K, std::unique_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;
+  }
+
+  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;
+  }
+
+  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/libchrome/base/containers/small_map.h b/libchrome/base/containers/small_map.h
new file mode 100644
index 0000000..82ed6c5
--- /dev/null
+++ b/libchrome/base/containers/small_map.h
@@ -0,0 +1,653 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <map>
+#include <string>
+#include <utility>
+
+#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.
+  static_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].InitFromMove(std::move(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].InitFromMove(std::move(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(std::move(*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/libchrome/base/containers/stack_container.h b/libchrome/base/containers/stack_container.h
new file mode 100644
index 0000000..9e0efc1
--- /dev/null
+++ b/libchrome/base/containers/stack_container.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_CONTAINERS_STACK_CONTAINER_H_
+#define BASE_CONTAINERS_STACK_CONTAINER_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/macros.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)
+    static_assert(ALIGNOF(T) <= 16, "http://crbug.com/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/libchrome/base/cpu.cc b/libchrome/base/cpu.cc
new file mode 100644
index 0000000..de4a001
--- /dev/null
+++ b/libchrome/base/cpu.cc
@@ -0,0 +1,238 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "base/macros.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_avx2_(false),
+    has_aesni_(false),
+    has_non_stop_time_stamp_counter_(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"
+    : "=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_t _xgetbv(uint32_t xcr) {
+  uint32_t eax, edx;
+
+  __asm__ volatile (
+    "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
+  return (static_cast<uint64_t>(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() {
+    // 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: ";
+
+    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)));
+      }
+    }
+  }
+
+  const std::string& brand() const { return brand_; }
+
+ private:
+  std::string brand_;
+  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) {
+    int cpu_info7[4] = {0};
+    __cpuid(cpu_info, 1);
+    if (num_ids >= 7) {
+      __cpuid(cpu_info7, 7);
+    }
+    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;
+    // 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_ =
+        (cpu_info[2] & 0x10000000) != 0 &&
+        (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;
+    has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 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());
+#endif
+}
+
+CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
+  if (has_avx2()) return AVX2;
+  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/libchrome/base/cpu.h b/libchrome/base/cpu.h
new file mode 100644
index 0000000..0e4303b
--- /dev/null
+++ b/libchrome/base/cpu.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_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,
+    AVX2,
+    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_; }
+  bool has_avx2() const { return has_avx2_; }
+  bool has_aesni() const { return has_aesni_; }
+  bool has_non_stop_time_stamp_counter() const {
+    return has_non_stop_time_stamp_counter_;
+  }
+
+  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_avx2_;
+  bool has_aesni_;
+  bool has_non_stop_time_stamp_counter_;
+  std::string cpu_vendor_;
+  std::string cpu_brand_;
+};
+
+}  // namespace base
+
+#endif  // BASE_CPU_H_
diff --git a/libchrome/base/cpu_unittest.cc b/libchrome/base/cpu_unittest.cc
new file mode 100644
index 0000000..ec14620
--- /dev/null
+++ b/libchrome/base/cpu_unittest.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/cpu.h"
+#include "build/build_config.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if _MSC_VER >= 1700
+// C4752: found Intel(R) Advanced Vector Extensions; consider using /arch:AVX.
+#pragma warning(disable: 4752)
+#endif
+
+// 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;
+
+  ASSERT_TRUE(cpu.has_mmx());
+  ASSERT_TRUE(cpu.has_sse());
+  ASSERT_TRUE(cpu.has_sse2());
+
+// GCC and clang instruction test.
+#if defined(COMPILER_GCC)
+  // Execute an MMX instruction.
+  __asm__ __volatile__("emms\n" : : : "mm0");
+
+  // Execute an SSE instruction.
+  __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
+
+  // 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");
+  }
+
+  if (cpu.has_avx()) {
+    // Execute an AVX instruction.
+    __asm__ __volatile__("vzeroupper\n" : : : "xmm0");
+  }
+
+  if (cpu.has_avx2()) {
+    // Execute an AVX 2 instruction.
+    __asm__ __volatile__("vpunpcklbw %%ymm0, %%ymm0, %%ymm0\n" : : : "xmm0");
+  }
+
+// Visual C 32 bit and ClangCL 32/64 bit test.
+#elif defined(COMPILER_MSVC) && (defined(ARCH_CPU_32_BITS) || \
+      (defined(ARCH_CPU_64_BITS) && defined(__clang__)))
+
+  // Execute an MMX instruction.
+  __asm emms;
+
+  // Execute an SSE instruction.
+  __asm xorps xmm0, xmm0;
+
+  // 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;
+  }
+
+// Visual C 2012 required for AVX.
+#if _MSC_VER >= 1700
+  if (cpu.has_avx()) {
+    // Execute an AVX instruction.
+    __asm vzeroupper;
+  }
+
+  if (cpu.has_avx2()) {
+    // Execute an AVX 2 instruction.
+    __asm vpunpcklbw ymm0, ymm0, ymm0
+  }
+#endif  // _MSC_VER >= 1700
+#endif  // defined(COMPILER_GCC)
+#endif  // defined(ARCH_CPU_X86_FAMILY)
+}
diff --git a/libchrome/base/critical_closure.h b/libchrome/base/critical_closure.h
new file mode 100644
index 0000000..6ebd7af
--- /dev/null
+++ b/libchrome/base/critical_closure.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_CRITICAL_CLOSURE_H_
+#define BASE_CRITICAL_CLOSURE_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "build/build_config.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/libchrome/base/debug/alias.cc b/libchrome/base/debug/alias.cc
new file mode 100644
index 0000000..ff35574
--- /dev/null
+++ b/libchrome/base/debug/alias.cc
@@ -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.
+
+#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*) {}
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", on)
+#endif
+
+}  // namespace debug
+}  // namespace base
diff --git a/libchrome/base/debug/alias.h b/libchrome/base/debug/alias.h
new file mode 100644
index 0000000..3b2ab64
--- /dev/null
+++ b/libchrome/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/libchrome/base/debug/debugger.cc b/libchrome/base/debug/debugger.cc
new file mode 100644
index 0000000..1ccee1c
--- /dev/null
+++ b/libchrome/base/debug/debugger.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/debug/debugger.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.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/libchrome/base/debug/debugger.h b/libchrome/base/debug/debugger.h
new file mode 100644
index 0000000..8680e28
--- /dev/null
+++ b/libchrome/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/libchrome/base/debug/debugger_posix.cc b/libchrome/base/debug/debugger_posix.cc
new file mode 100644
index 0000000..a157d9a
--- /dev/null
+++ b/libchrome/base/debug/debugger_posix.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#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/debug/alias.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_piece.h"
+
+#if defined(USE_SYMBOLIZE)
+#error "symbolize support was removed from libchrome"
+#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.
+
+  // Linker's ICF feature may merge this function with other functions with the
+  // same definition (e.g. any function whose sole job is to call abort()) and
+  // it may confuse the crash report processing system. http://crbug.com/508489
+  static int static_variable_to_make_this_function_unique = 0;
+  base::debug::Alias(&static_variable_to_make_this_function_unique);
+
+  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/libchrome/base/debug/debugger_unittest.cc b/libchrome/base/debug/debugger_unittest.cc
new file mode 100644
index 0000000..0a5a039
--- /dev/null
+++ b/libchrome/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/libchrome/base/debug/debugging_flags.h b/libchrome/base/debug/debugging_flags.h
new file mode 100644
index 0000000..1ea435f
--- /dev/null
+++ b/libchrome/base/debug/debugging_flags.h
@@ -0,0 +1,11 @@
+// Generated by build/write_buildflag_header.py
+// From "base_debugging_flags"
+
+#ifndef BASE_DEBUG_DEBUGGING_FLAGS_H_
+#define BASE_DEBUG_DEBUGGING_FLAGS_H_
+
+#include "build/buildflag.h"
+
+#define BUILDFLAG_INTERNAL_ENABLE_PROFILING() (0)
+
+#endif  // BASE_DEBUG_DEBUGGING_FLAGS_H_
diff --git a/libchrome/base/debug/leak_annotations.h b/libchrome/base/debug/leak_annotations.h
new file mode 100644
index 0000000..dc50246
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/debug/leak_tracker.h b/libchrome/base/debug/leak_tracker.h
new file mode 100644
index 0000000..9dd1622
--- /dev/null
+++ b/libchrome/base/debug/leak_tracker.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_DEBUG_LEAK_TRACKER_H_
+#define BASE_DEBUG_LEAK_TRACKER_H_
+
+#include <stddef.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/libchrome/base/debug/leak_tracker_unittest.cc b/libchrome/base/debug/leak_tracker_unittest.cc
new file mode 100644
index 0000000..8b4c568
--- /dev/null
+++ b/libchrome/base/debug/leak_tracker_unittest.cc
@@ -0,0 +1,115 @@
+// 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 <memory>
+
+#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.
+  std::unique_ptr<ClassA> a1(new ClassA);
+  std::unique_ptr<ClassB> b1(new ClassB);
+  std::unique_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());
+
+    std::unique_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());
+
+  std::unique_ptr<ClassA> a1(new ClassA);
+  std::unique_ptr<ClassA> a2(new ClassA);
+  std::unique_ptr<ClassA> a3(new ClassA);
+  std::unique_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).
+  std::unique_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/libchrome/base/debug/proc_maps_linux.h b/libchrome/base/debug/proc_maps_linux.h
new file mode 100644
index 0000000..38e9231
--- /dev/null
+++ b/libchrome/base/debug/proc_maps_linux.h
@@ -0,0 +1,91 @@
+// 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 <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.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_t 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/libchrome/base/debug/stack_trace.cc b/libchrome/base/debug/stack_trace.cc
new file mode 100644
index 0000000..ac0ead7
--- /dev/null
+++ b/libchrome/base/debug/stack_trace.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/debug/stack_trace.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <sstream>
+
+#include "base/macros.h"
+
+#if HAVE_TRACE_STACK_FRAME_POINTERS && defined(OS_ANDROID)
+#include <pthread.h>
+#include "base/process/process_handle.h"
+#include "base/threading/platform_thread.h"
+#endif
+
+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();
+}
+
+#if HAVE_TRACE_STACK_FRAME_POINTERS
+
+#if defined(OS_ANDROID)
+
+static uintptr_t GetStackEnd() {
+  // Bionic reads proc/maps on every call to pthread_getattr_np() when called
+  // from the main thread. So we need to cache end of stack in that case to get
+  // acceptable performance.
+  // For all other threads pthread_getattr_np() is fast enough as it just reads
+  // values from its pthread_t argument.
+  static uintptr_t main_stack_end = 0;
+
+  bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId();
+
+  if (is_main_thread && main_stack_end) {
+    return main_stack_end;
+  }
+
+  uintptr_t stack_begin = 0;
+  size_t stack_size = 0;
+  pthread_attr_t attributes;
+  int error = pthread_getattr_np(pthread_self(), &attributes);
+  if (!error) {
+    error = pthread_attr_getstack(
+        &attributes,
+        reinterpret_cast<void**>(&stack_begin),
+        &stack_size);
+    pthread_attr_destroy(&attributes);
+  }
+  DCHECK(!error);
+
+  uintptr_t stack_end = stack_begin + stack_size;
+  if (is_main_thread) {
+    main_stack_end = stack_end;
+  }
+  return stack_end;
+}
+
+#endif  // defined(OS_ANDROID)
+
+size_t TraceStackFramePointers(const void** out_trace,
+                               size_t max_depth,
+                               size_t skip_initial) {
+  // Usage of __builtin_frame_address() enables frame pointers in this
+  // function even if they are not enabled globally. So 'sp' will always
+  // be valid.
+  uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
+
+#if defined(OS_ANDROID)
+  uintptr_t stack_end = GetStackEnd();
+#endif
+
+  size_t depth = 0;
+  while (depth < max_depth) {
+#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__)
+    // GCC and LLVM generate slightly different frames on ARM, see
+    // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates
+    // x86-compatible frame, while GCC needs adjustment.
+    sp -= sizeof(uintptr_t);
+#endif
+
+#if defined(OS_ANDROID)
+    // Both sp[0] and s[1] must be valid.
+    if (sp + 2 * sizeof(uintptr_t) > stack_end) {
+      break;
+    }
+#endif
+
+    if (skip_initial != 0) {
+      skip_initial--;
+    } else {
+      out_trace[depth++] = reinterpret_cast<const void**>(sp)[1];
+    }
+
+    // Find out next frame pointer
+    // (heuristics are from TCMalloc's stacktrace functions)
+    {
+      uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0];
+
+      // With the stack growing downwards, older stack frame must be
+      // at a greater address that the current one.
+      if (next_sp <= sp) break;
+
+      // Assume stack frames larger than 100,000 bytes are bogus.
+      if (next_sp - sp > 100000) break;
+
+      // Check alignment.
+      if (sp & (sizeof(void*) - 1)) break;
+
+      sp = next_sp;
+    }
+  }
+
+  return depth;
+}
+
+#endif  // HAVE_TRACE_STACK_FRAME_POINTERS
+
+}  // namespace debug
+}  // namespace base
diff --git a/libchrome/base/debug/stack_trace.h b/libchrome/base/debug/stack_trace.h
new file mode 100644
index 0000000..23e7b51
--- /dev/null
+++ b/libchrome/base/debug/stack_trace.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_DEBUG_STACK_TRACE_H_
+#define BASE_DEBUG_STACK_TRACE_H_
+
+#include <stddef.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
+
+#if defined(OS_POSIX) && ( \
+    defined(__i386__) || defined(__x86_64__) || \
+    (defined(__arm__) && !defined(__thumb__)))
+#define HAVE_TRACE_STACK_FRAME_POINTERS 1
+#else
+#define HAVE_TRACE_STACK_FRAME_POINTERS 0
+#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.
+// In sandboxed processes, this has to be called before the sandbox is turned
+// on.
+// Calling this function on Linux opens /proc/self/maps and caches its
+// contents. In non-official 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 EnableInProcessStackDumping();
+
+// 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(_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(const _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_;
+};
+
+#if HAVE_TRACE_STACK_FRAME_POINTERS
+// Traces the stack by using frame pointers. This function is faster but less
+// reliable than StackTrace. It should work for debug and profiling builds,
+// but not for release builds (although there are some exceptions).
+//
+// Writes at most |max_depth| frames (instruction pointers) into |out_trace|
+// after skipping |skip_initial| frames. Note that the function itself is not
+// added to the trace so |skip_initial| should be 0 in most cases.
+// Returns number of frames written.
+BASE_EXPORT size_t TraceStackFramePointers(const void** out_trace,
+                                           size_t max_depth,
+                                           size_t skip_initial);
+#endif  // HAVE_TRACE_STACK_FRAME_POINTERS
+
+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/libchrome/base/debug/stack_trace_posix.cc b/libchrome/base/debug/stack_trace_posix.cc
new file mode 100644
index 0000000..3c0299c
--- /dev/null
+++ b/libchrome/base/debug/stack_trace_posix.cc
@@ -0,0 +1,819 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.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 <memory>
+#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/debug/debugger.h"
+#include "base/debug/proc_maps_linux.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/free_deleter.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)
+#error "symbolize support was removed from libchrome"
+#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]"
+#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
+void DemangleSymbols(std::string* text) {
+  // Note: code in this function is NOT async-signal safe (std::string uses
+  // malloc internally).
+  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;
+    std::unique_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;
+    }
+  }
+}
+#elif !defined(__UCLIBC__)
+void DemangleSymbols(std::string* /* text */) {}
+#endif  // defined(__GLIBCXX__) && !defined(__UCLIBC__)
+
+#endif  // !defined(USE_SYMBOLIZE)
+
+class BacktraceOutputHandler {
+ public:
+  virtual void HandleOutput(const char* output) = 0;
+
+ protected:
+  virtual ~BacktraceOutputHandler() {}
+};
+
+#if defined(USE_SYMBOLIZE) || !defined(__UCLIBC__)
+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);
+}
+#endif  // defined(USE_SYMBOLIZE) ||  !defined(__UCLIBC__)
+
+#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)
+
+#if !defined(__UCLIBC__)
+void ProcessBacktrace(void *const * trace,
+                      size_t size,
+                      BacktraceOutputHandler* handler) {
+  (void)trace;  // unused based on build context below.
+  (void)size;  // unusud based on build context below.
+  (void)handler;  // unused based on build context below.
+  // 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");
+  }
+#else
+  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) {
+    std::unique_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)
+}
+#endif  // !defined(__UCLIBC__)
+
+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) {
+  (void)void_context;  // unused depending on build 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");
+
+#if defined(CFI_ENFORCEMENT)
+  if (signal == SIGILL && info->si_code == ILL_ILLOPN) {
+    PrintToStderr(
+        "CFI: Most likely a control flow integrity violation; for more "
+        "information see:\n");
+    PrintToStderr(
+        "https://www.chromium.org/developers/testing/control-flow-integrity\n");
+  }
+#endif
+
+  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  // ARCH_CPU_32_BITS
+  };
+
+#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  // ARCH_CPU_X86_FAMILY
+#endif  // defined(OS_LINUX)
+
+  PrintToStderr("[end of stack trace]\n");
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  if (::signal(signal, SIG_DFL) == SIG_ERR)
+    _exit(1);
+#else
+  // Non-Mac OSes should probably reraise the signal as well, but the Linux
+  // sandbox tests break on CrOS devices.
+  // https://code.google.com/p/chromium/issues/detail?id=551681
+  _exit(1);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+}
+
+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
+  // successfully 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(OFFICIAL_BUILD)
+    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(OFFICIAL_BUILD)
+
+    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 safe for production builds.  Hence it is only done in non-official
+    // builds.  For more details, take a look at: http://crbug.com/341966.
+#if !defined(OFFICIAL_BUILD)
+    // 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(OFFICIAL_BUILD)
+  }
+
+  // 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(OFFICIAL_BUILD)
+    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(OFFICIAL_BUILD)
+  }
+
+  // Set to true upon successful initialization.
+  bool is_initialized_;
+
+#if !defined(OFFICIAL_BUILD)
+  // 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 production builds.
+  std::map<std::string, int> modules_;
+#endif  // !defined(OFFICIAL_BUILD)
+
+  // 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 EnableInProcessStackDumping() {
+#if defined(USE_SYMBOLIZE)
+  SandboxSymbolizeHelper::GetInstance();
+#endif  // USE_SYMBOLIZE
+
+  // 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) {
+    // This does "j = -i" while avoiding integer overflow.
+    j = static_cast<uintptr_t>(-(i + 1)) + 1;
+
+    // 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/libchrome/base/debug/task_annotator.cc b/libchrome/base/debug/task_annotator.cc
new file mode 100644
index 0000000..4ba4d91
--- /dev/null
+++ b/libchrome/base/debug/task_annotator.cc
@@ -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.
+
+#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_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                          queue_function,
+                          TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+                          TRACE_EVENT_FLAG_FLOW_OUT);
+}
+
+void TaskAnnotator::RunTask(const char* queue_function,
+                            const PendingTask& pending_task) {
+  tracked_objects::TaskStopwatch stopwatch;
+  stopwatch.Start();
+  tracked_objects::Duration queue_duration =
+      stopwatch.StartTime() - pending_task.EffectiveTimePosted();
+
+  TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                          queue_function,
+                          TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+                          TRACE_EVENT_FLAG_FLOW_IN,
+                          "queue_duration",
+                          queue_duration.InMilliseconds());
+
+  // 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_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
+  return (static_cast<uint64_t>(task.sequence_num) << 32) |
+         ((static_cast<uint64_t>(reinterpret_cast<intptr_t>(this)) << 32) >>
+          32);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/libchrome/base/debug/task_annotator.h b/libchrome/base/debug/task_annotator.h
new file mode 100644
index 0000000..2687c5c
--- /dev/null
+++ b/libchrome/base/debug/task_annotator.h
@@ -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.
+
+#ifndef BASE_DEBUG_TASK_ANNOTATOR_H_
+#define BASE_DEBUG_TASK_ANNOTATOR_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/macros.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.
+  void RunTask(const char* queue_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_t GetTaskTraceID(const PendingTask& task) const;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
+};
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_TASK_ANNOTATOR_H_
diff --git a/libchrome/base/debug/task_annotator_unittest.cc b/libchrome/base/debug/task_annotator_unittest.cc
new file mode 100644
index 0000000..9f5c442
--- /dev/null
+++ b/libchrome/base/debug/task_annotator_unittest.cc
@@ -0,0 +1,32 @@
+// 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", pending_task);
+  EXPECT_EQ(123, result);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/libchrome/base/environment.cc b/libchrome/base/environment.cc
new file mode 100644
index 0000000..534a7a8
--- /dev/null
+++ b/libchrome/base/environment.cc
@@ -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.
+
+#include "base/environment.h"
+
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.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(StringPiece 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 (IsAsciiLower(first_char))
+      alternate_case_var = ToUpperASCII(variable_name);
+    else if (IsAsciiUpper(first_char))
+      alternate_case_var = ToLowerASCII(variable_name);
+    else
+      return false;
+    return GetVarImpl(alternate_case_var.c_str(), result);
+  }
+
+  bool SetVar(StringPiece variable_name,
+              const std::string& new_value) override {
+    return SetVarImpl(variable_name, new_value);
+  }
+
+  bool UnSetVar(StringPiece variable_name) override {
+    return UnSetVarImpl(variable_name);
+  }
+
+ private:
+  bool GetVarImpl(StringPiece variable_name, std::string* result) {
+#if defined(OS_POSIX)
+    const char* env_value = getenv(variable_name.data());
+    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(), nullptr, 0);
+    if (value_length == 0)
+      return false;
+    if (result) {
+      std::unique_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(StringPiece variable_name, const std::string& new_value) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !setenv(variable_name.data(), 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(StringPiece variable_name) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !unsetenv(variable_name.data());
+#elif defined(OS_WIN)
+    // On success, a nonzero value is returned.
+    return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), nullptr);
+#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
+std::unique_ptr<Environment> Environment::Create() {
+  return MakeUnique<EnvironmentImpl>();
+}
+
+bool Environment::HasVar(StringPiece variable_name) {
+  return GetVar(variable_name, nullptr);
+}
+
+#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)
+
+std::unique_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.
+  std::unique_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;
+}
+
+#endif  // OS_POSIX
+
+}  // namespace base
diff --git a/libchrome/base/environment.h b/libchrome/base/environment.h
new file mode 100644
index 0000000..3a4ed04
--- /dev/null
+++ b/libchrome/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 <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.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();
+
+  // Returns the appropriate platform-specific instance.
+  static std::unique_ptr<Environment> Create();
+
+  // Gets an environment variable's value and stores it in |result|.
+  // Returns false if the key is unset.
+  virtual bool GetVar(StringPiece variable_name, std::string* result) = 0;
+
+  // Syntactic sugar for GetVar(variable_name, nullptr);
+  virtual bool HasVar(StringPiece variable_name);
+
+  // Returns true on success, otherwise returns false.
+  virtual bool SetVar(StringPiece variable_name,
+                      const std::string& new_value) = 0;
+
+  // Returns true on success, otherwise returns false.
+  virtual bool UnSetVar(StringPiece 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 std::unique_ptr<char* []> AlterEnvironment(
+    const char* const* env,
+    const EnvironmentMap& changes);
+
+#endif
+
+}  // namespace base
+
+#endif  // BASE_ENVIRONMENT_H_
diff --git a/libchrome/base/environment_unittest.cc b/libchrome/base/environment_unittest.cc
new file mode 100644
index 0000000..ef264cf
--- /dev/null
+++ b/libchrome/base/environment_unittest.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/environment.h"
+
+#include <memory>
+
+#include "build/build_config.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...
+  std::unique_ptr<Environment> env(Environment::Create());
+  std::string env_value;
+  EXPECT_TRUE(env->GetVar("PATH", &env_value));
+  EXPECT_NE(env_value, "");
+}
+
+TEST_F(EnvironmentTest, GetVarReverse) {
+  std::unique_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...
+  std::unique_ptr<Environment> env(Environment::Create());
+  EXPECT_TRUE(env->HasVar("PATH"));
+}
+
+TEST_F(EnvironmentTest, SetVar) {
+  std::unique_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) {
+  std::unique_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;
+  std::unique_ptr<char* []> e;
+
+  e = AlterEnvironment(empty, changes);
+  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/libchrome/base/event_types.h b/libchrome/base/event_types.h
new file mode 100644
index 0000000..9905800
--- /dev/null
+++ b/libchrome/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/libchrome/base/feature_list.cc b/libchrome/base/feature_list.cc
new file mode 100644
index 0000000..435165e
--- /dev/null
+++ b/libchrome/base/feature_list.cc
@@ -0,0 +1,306 @@
+// 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/feature_list.h"
+
+#include <stddef.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+namespace {
+
+// Pointer to the FeatureList instance singleton that was set via
+// FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
+// have more control over initialization timing. Leaky.
+FeatureList* g_instance = nullptr;
+
+// Tracks whether the FeatureList instance was initialized via an accessor.
+bool g_initialized_from_accessor = false;
+
+// Some characters are not allowed to appear in feature names or the associated
+// field trial names, as they are used as special characters for command-line
+// serialization. This function checks that the strings are ASCII (since they
+// are used in command-line API functions that require ASCII) and whether there
+// are any reserved characters present, returning true if the string is valid.
+// Only called in DCHECKs.
+bool IsValidFeatureOrFieldTrialName(const std::string& name) {
+  return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
+}
+
+}  // namespace
+
+FeatureList::FeatureList() {}
+
+FeatureList::~FeatureList() {}
+
+void FeatureList::InitializeFromCommandLine(
+    const std::string& enable_features,
+    const std::string& disable_features) {
+  DCHECK(!initialized_);
+
+  // Process disabled features first, so that disabled ones take precedence over
+  // enabled ones (since RegisterOverride() uses insert()).
+  RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
+  RegisterOverridesFromCommandLine(enable_features, OVERRIDE_ENABLE_FEATURE);
+
+  initialized_from_command_line_ = true;
+}
+
+bool FeatureList::IsFeatureOverriddenFromCommandLine(
+    const std::string& feature_name,
+    OverrideState state) const {
+  auto it = overrides_.find(feature_name);
+  return it != overrides_.end() && it->second.overridden_state == state &&
+         !it->second.overridden_by_field_trial;
+}
+
+void FeatureList::AssociateReportingFieldTrial(
+    const std::string& feature_name,
+    OverrideState for_overridden_state,
+    FieldTrial* field_trial) {
+  DCHECK(
+      IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state));
+
+  // Only one associated field trial is supported per feature. This is generally
+  // enforced server-side.
+  OverrideEntry* entry = &overrides_.find(feature_name)->second;
+  if (entry->field_trial) {
+    NOTREACHED() << "Feature " << feature_name
+                 << " already has trial: " << entry->field_trial->trial_name()
+                 << ", associating trial: " << field_trial->trial_name();
+    return;
+  }
+
+  entry->field_trial = field_trial;
+}
+
+void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
+                                             OverrideState override_state,
+                                             FieldTrial* field_trial) {
+  DCHECK(field_trial);
+  DCHECK(!ContainsKey(overrides_, feature_name) ||
+         !overrides_.find(feature_name)->second.field_trial)
+      << "Feature " << feature_name
+      << " has conflicting field trial overrides: "
+      << overrides_.find(feature_name)->second.field_trial->trial_name()
+      << " / " << field_trial->trial_name();
+
+  RegisterOverride(feature_name, override_state, field_trial);
+}
+
+void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
+                                      std::string* disable_overrides) {
+  DCHECK(initialized_);
+
+  enable_overrides->clear();
+  disable_overrides->clear();
+
+  // Note: Since |overrides_| is a std::map, iteration will be in alphabetical
+  // order. This not guaranteed to users of this function, but is useful for
+  // tests to assume the order.
+  for (const auto& entry : overrides_) {
+    std::string* target_list = nullptr;
+    switch (entry.second.overridden_state) {
+      case OVERRIDE_USE_DEFAULT:
+      case OVERRIDE_ENABLE_FEATURE:
+        target_list = enable_overrides;
+        break;
+      case OVERRIDE_DISABLE_FEATURE:
+        target_list = disable_overrides;
+        break;
+    }
+
+    if (!target_list->empty())
+      target_list->push_back(',');
+    if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT)
+      target_list->push_back('*');
+    target_list->append(entry.first);
+    if (entry.second.field_trial) {
+      target_list->push_back('<');
+      target_list->append(entry.second.field_trial->trial_name());
+    }
+  }
+}
+
+// static
+bool FeatureList::IsEnabled(const Feature& feature) {
+  if (!g_instance) {
+    g_initialized_from_accessor = true;
+    return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
+  }
+  return g_instance->IsFeatureEnabled(feature);
+}
+
+// static
+FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) {
+  return GetInstance()->GetAssociatedFieldTrial(feature);
+}
+
+// static
+std::vector<std::string> FeatureList::SplitFeatureListString(
+    const std::string& input) {
+  return SplitString(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+}
+
+// static
+bool FeatureList::InitializeInstance(const std::string& enable_features,
+                                     const std::string& disable_features) {
+  // We want to initialize a new instance here to support command-line features
+  // in testing better. For example, we initialize a dummy instance in
+  // base/test/test_suite.cc, and override it in content/browser/
+  // browser_main_loop.cc.
+  // On the other hand, we want to avoid re-initialization from command line.
+  // For example, we initialize an instance in chrome/browser/
+  // chrome_browser_main.cc and do not override it in content/browser/
+  // browser_main_loop.cc.
+  // If the singleton was previously initialized from within an accessor, we
+  // want to prevent callers from reinitializing the singleton and masking the
+  // accessor call(s) which likely returned incorrect information.
+  CHECK(!g_initialized_from_accessor);
+  bool instance_existed_before = false;
+  if (g_instance) {
+    if (g_instance->initialized_from_command_line_)
+      return false;
+
+    delete g_instance;
+    g_instance = nullptr;
+    instance_existed_before = true;
+  }
+
+  std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  feature_list->InitializeFromCommandLine(enable_features, disable_features);
+  base::FeatureList::SetInstance(std::move(feature_list));
+  return !instance_existed_before;
+}
+
+// static
+FeatureList* FeatureList::GetInstance() {
+  return g_instance;
+}
+
+// static
+void FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
+  DCHECK(!g_instance);
+  instance->FinalizeInitialization();
+
+  // Note: Intentional leak of global singleton.
+  g_instance = instance.release();
+}
+
+// static
+void FeatureList::ClearInstanceForTesting() {
+  delete g_instance;
+  g_instance = nullptr;
+  g_initialized_from_accessor = false;
+}
+
+void FeatureList::FinalizeInitialization() {
+  DCHECK(!initialized_);
+  initialized_ = true;
+}
+
+bool FeatureList::IsFeatureEnabled(const Feature& feature) {
+  DCHECK(initialized_);
+  DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
+  DCHECK(CheckFeatureIdentity(feature)) << feature.name;
+
+  auto it = overrides_.find(feature.name);
+  if (it != overrides_.end()) {
+    const OverrideEntry& entry = it->second;
+
+    // Activate the corresponding field trial, if necessary.
+    if (entry.field_trial)
+      entry.field_trial->group();
+
+    // TODO(asvitkine) Expand this section as more support is added.
+
+    // If marked as OVERRIDE_USE_DEFAULT, simply return the default state below.
+    if (entry.overridden_state != OVERRIDE_USE_DEFAULT)
+      return entry.overridden_state == OVERRIDE_ENABLE_FEATURE;
+  }
+  // Otherwise, return the default state.
+  return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
+}
+
+FieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) {
+  DCHECK(initialized_);
+  DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
+  DCHECK(CheckFeatureIdentity(feature)) << feature.name;
+
+  auto it = overrides_.find(feature.name);
+  if (it != overrides_.end()) {
+    const OverrideEntry& entry = it->second;
+    return entry.field_trial;
+  }
+
+  return nullptr;
+}
+
+void FeatureList::RegisterOverridesFromCommandLine(
+    const std::string& feature_list,
+    OverrideState overridden_state) {
+  for (const auto& value : SplitFeatureListString(feature_list)) {
+    StringPiece feature_name(value);
+    base::FieldTrial* trial = nullptr;
+
+    // The entry may be of the form FeatureName<FieldTrialName - in which case,
+    // this splits off the field trial name and associates it with the override.
+    std::string::size_type pos = feature_name.find('<');
+    if (pos != std::string::npos) {
+      feature_name.set(value.data(), pos);
+      trial = base::FieldTrialList::Find(value.substr(pos + 1));
+    }
+
+    RegisterOverride(feature_name, overridden_state, trial);
+  }
+}
+
+void FeatureList::RegisterOverride(StringPiece feature_name,
+                                   OverrideState overridden_state,
+                                   FieldTrial* field_trial) {
+  DCHECK(!initialized_);
+  if (field_trial) {
+    DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
+        << field_trial->trial_name();
+  }
+  if (feature_name.starts_with("*")) {
+    feature_name = feature_name.substr(1);
+    overridden_state = OVERRIDE_USE_DEFAULT;
+  }
+
+  // Note: The semantics of insert() is that it does not overwrite the entry if
+  // one already exists for the key. Thus, only the first override for a given
+  // feature name takes effect.
+  overrides_.insert(std::make_pair(
+      feature_name.as_string(), OverrideEntry(overridden_state, field_trial)));
+}
+
+bool FeatureList::CheckFeatureIdentity(const Feature& feature) {
+  AutoLock auto_lock(feature_identity_tracker_lock_);
+
+  auto it = feature_identity_tracker_.find(feature.name);
+  if (it == feature_identity_tracker_.end()) {
+    // If it's not tracked yet, register it.
+    feature_identity_tracker_[feature.name] = &feature;
+    return true;
+  }
+  // Compare address of |feature| to the existing tracked entry.
+  return it->second == &feature;
+}
+
+FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
+                                          FieldTrial* field_trial)
+    : overridden_state(overridden_state),
+      field_trial(field_trial),
+      overridden_by_field_trial(field_trial != nullptr) {}
+
+}  // namespace base
diff --git a/libchrome/base/feature_list.h b/libchrome/base/feature_list.h
new file mode 100644
index 0000000..e9ed00a
--- /dev/null
+++ b/libchrome/base/feature_list.h
@@ -0,0 +1,260 @@
+// 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_FEATURE_LIST_H_
+#define BASE_FEATURE_LIST_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class FieldTrial;
+
+// Specifies whether a given feature is enabled or disabled by default.
+enum FeatureState {
+  FEATURE_DISABLED_BY_DEFAULT,
+  FEATURE_ENABLED_BY_DEFAULT,
+};
+
+// The Feature struct is used to define the default state for a feature. See
+// comment below for more details. There must only ever be one struct instance
+// for a given feature name - generally defined as a constant global variable or
+// file static.
+struct BASE_EXPORT Feature {
+  // The name of the feature. This should be unique to each feature and is used
+  // for enabling/disabling features via command line flags and experiments.
+  const char* const name;
+
+  // The default state (i.e. enabled or disabled) for this feature.
+  const FeatureState default_state;
+};
+
+// The FeatureList class is used to determine whether a given feature is on or
+// off. It provides an authoritative answer, taking into account command-line
+// overrides and experimental control.
+//
+// The basic use case is for any feature that can be toggled (e.g. through
+// command-line or an experiment) to have a defined Feature struct, e.g.:
+//
+//   const base::Feature kMyGreatFeature {
+//     "MyGreatFeature", base::FEATURE_ENABLED_BY_DEFAULT
+//   };
+//
+// Then, client code that wishes to query the state of the feature would check:
+//
+//   if (base::FeatureList::IsEnabled(kMyGreatFeature)) {
+//     // Feature code goes here.
+//   }
+//
+// Behind the scenes, the above call would take into account any command-line
+// flags to enable or disable the feature, any experiments that may control it
+// and finally its default state (in that order of priority), to determine
+// whether the feature is on.
+//
+// Features can be explicitly forced on or off by specifying a list of comma-
+// separated feature names via the following command-line flags:
+//
+//   --enable-features=Feature5,Feature7
+//   --disable-features=Feature1,Feature2,Feature3
+//
+// After initialization (which should be done single-threaded), the FeatureList
+// API is thread safe.
+//
+// Note: This class is a singleton, but does not use base/memory/singleton.h in
+// order to have control over its initialization sequence. Specifically, the
+// intended use is to create an instance of this class and fully initialize it,
+// before setting it as the singleton for a process, via SetInstance().
+class BASE_EXPORT FeatureList {
+ public:
+  FeatureList();
+  ~FeatureList();
+
+  // Initializes feature overrides via command-line flags |enable_features| and
+  // |disable_features|, each of which is a comma-separated list of features to
+  // enable or disable, respectively. If a feature appears on both lists, then
+  // it will be disabled. If a list entry has the format "FeatureName<TrialName"
+  // then this initialization will also associate the feature state override
+  // with the named field trial, if it exists. If a feature name is prefixed
+  // with the '*' character, it will be created with OVERRIDE_USE_DEFAULT -
+  // which is useful for associating with a trial while using the default state.
+  // Must only be invoked during the initialization phase (before
+  // FinalizeInitialization() has been called).
+  void InitializeFromCommandLine(const std::string& enable_features,
+                                 const std::string& disable_features);
+
+  // Specifies whether a feature override enables or disables the feature.
+  enum OverrideState {
+    OVERRIDE_USE_DEFAULT,
+    OVERRIDE_DISABLE_FEATURE,
+    OVERRIDE_ENABLE_FEATURE,
+  };
+
+  // Returns true if the state of |feature_name| has been overridden via
+  // |InitializeFromCommandLine()|.
+  bool IsFeatureOverriddenFromCommandLine(const std::string& feature_name,
+                                          OverrideState state) const;
+
+  // Associates a field trial for reporting purposes corresponding to the
+  // command-line setting the feature state to |for_overridden_state|. The trial
+  // will be activated when the state of the feature is first queried. This
+  // should be called during registration, after InitializeFromCommandLine() has
+  // been called but before the instance is registered via SetInstance().
+  void AssociateReportingFieldTrial(const std::string& feature_name,
+                                    OverrideState for_overridden_state,
+                                    FieldTrial* field_trial);
+
+  // Registers a field trial to override the enabled state of the specified
+  // feature to |override_state|. Command-line overrides still take precedence
+  // over field trials, so this will have no effect if the feature is being
+  // overridden from the command-line. The associated field trial will be
+  // activated when the feature state for this feature is queried. This should
+  // be called during registration, after InitializeFromCommandLine() has been
+  // called but before the instance is registered via SetInstance().
+  void RegisterFieldTrialOverride(const std::string& feature_name,
+                                  OverrideState override_state,
+                                  FieldTrial* field_trial);
+
+  // Returns comma-separated lists of feature names (in the same format that is
+  // accepted by InitializeFromCommandLine()) corresponding to features that
+  // have been overridden - either through command-line or via FieldTrials. For
+  // those features that have an associated FieldTrial, the output entry will be
+  // of the format "FeatureName<TrialName", where "TrialName" is the name of the
+  // FieldTrial. Features that have overrides with OVERRIDE_USE_DEFAULT will be
+  // added to |enable_overrides| with a '*' character prefix. Must be called
+  // only after the instance has been initialized and registered.
+  void GetFeatureOverrides(std::string* enable_overrides,
+                           std::string* disable_overrides);
+
+  // Returns whether the given |feature| is enabled. Must only be called after
+  // the singleton instance has been registered via SetInstance(). Additionally,
+  // a feature with a given name must only have a single corresponding Feature
+  // struct, which is checked in builds with DCHECKs enabled.
+  static bool IsEnabled(const Feature& feature);
+
+  // Returns the field trial associated with the given |feature|. Must only be
+  // called after the singleton instance has been registered via SetInstance().
+  static FieldTrial* GetFieldTrial(const Feature& feature);
+
+  // Splits a comma-separated string containing feature names into a vector.
+  static std::vector<std::string> SplitFeatureListString(
+      const std::string& input);
+
+  // Initializes and sets an instance of FeatureList with feature overrides via
+  // command-line flags |enable_features| and |disable_features| if one has not
+  // already been set from command-line flags. Returns true if an instance did
+  // not previously exist. See InitializeFromCommandLine() for more details
+  // about |enable_features| and |disable_features| parameters.
+  static bool InitializeInstance(const std::string& enable_features,
+                                 const std::string& disable_features);
+
+  // Returns the singleton instance of FeatureList. Will return null until an
+  // instance is registered via SetInstance().
+  static FeatureList* GetInstance();
+
+  // Registers the given |instance| to be the singleton feature list for this
+  // process. This should only be called once and |instance| must not be null.
+  static void SetInstance(std::unique_ptr<FeatureList> instance);
+
+  // Clears the previously-registered singleton instance for tests.
+  static void ClearInstanceForTesting();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
+
+  struct OverrideEntry {
+    // The overridden enable (on/off) state of the feature.
+    const OverrideState overridden_state;
+
+    // An optional associated field trial, which will be activated when the
+    // state of the feature is queried for the first time. Weak pointer to the
+    // FieldTrial object that is owned by the FieldTrialList singleton.
+    base::FieldTrial* field_trial;
+
+    // Specifies whether the feature's state is overridden by |field_trial|.
+    // If it's not, and |field_trial| is not null, it means it is simply an
+    // associated field trial for reporting purposes (and |overridden_state|
+    // came from the command-line).
+    const bool overridden_by_field_trial;
+
+    // TODO(asvitkine): Expand this as more support is added.
+
+    // Constructs an OverrideEntry for the given |overridden_state|. If
+    // |field_trial| is not null, it implies that |overridden_state| comes from
+    // the trial, so |overridden_by_field_trial| will be set to true.
+    OverrideEntry(OverrideState overridden_state, FieldTrial* field_trial);
+  };
+
+  // Finalizes the initialization state of the FeatureList, so that no further
+  // overrides can be registered. This is called by SetInstance() on the
+  // singleton feature list that is being registered.
+  void FinalizeInitialization();
+
+  // Returns whether the given |feature| is enabled. This is invoked by the
+  // public FeatureList::IsEnabled() static function on the global singleton.
+  // Requires the FeatureList to have already been fully initialized.
+  bool IsFeatureEnabled(const Feature& feature);
+
+  // Returns the field trial associated with the given |feature|. This is
+  // invoked by the public FeatureList::GetFieldTrial() static function on the
+  // global singleton. Requires the FeatureList to have already been fully
+  // initialized.
+  base::FieldTrial* GetAssociatedFieldTrial(const Feature& feature);
+
+  // For each feature name in comma-separated list of strings |feature_list|,
+  // registers an override with the specified |overridden_state|. Also, will
+  // associate an optional named field trial if the entry is of the format
+  // "FeatureName<TrialName".
+  void RegisterOverridesFromCommandLine(const std::string& feature_list,
+                                        OverrideState overridden_state);
+
+  // Registers an override for feature |feature_name|. The override specifies
+  // whether the feature should be on or off (via |overridden_state|), which
+  // will take precedence over the feature's default state. If |field_trial| is
+  // not null, registers the specified field trial object to be associated with
+  // the feature, which will activate the field trial when the feature state is
+  // queried. If an override is already registered for the given feature, it
+  // will not be changed.
+  void RegisterOverride(StringPiece feature_name,
+                        OverrideState overridden_state,
+                        FieldTrial* field_trial);
+
+  // Verifies that there's only a single definition of a Feature struct for a
+  // given feature name. Keeps track of the first seen Feature struct for each
+  // feature. Returns false when called on a Feature struct with a different
+  // address than the first one it saw for that feature name. Used only from
+  // DCHECKs and tests.
+  bool CheckFeatureIdentity(const Feature& feature);
+
+  // Map from feature name to an OverrideEntry struct for the feature, if it
+  // exists.
+  std::map<std::string, OverrideEntry> overrides_;
+
+  // Locked map that keeps track of seen features, to ensure a single feature is
+  // only defined once. This verification is only done in builds with DCHECKs
+  // enabled.
+  Lock feature_identity_tracker_lock_;
+  std::map<std::string, const Feature*> feature_identity_tracker_;
+
+  // Whether this object has been fully initialized. This gets set to true as a
+  // result of FinalizeInitialization().
+  bool initialized_ = false;
+
+  // Whether this object has been initialized from command line.
+  bool initialized_from_command_line_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(FeatureList);
+};
+
+}  // namespace base
+
+#endif  // BASE_FEATURE_LIST_H_
diff --git a/libchrome/base/feature_list_unittest.cc b/libchrome/base/feature_list_unittest.cc
new file mode 100644
index 0000000..9d1dcb7
--- /dev/null
+++ b/libchrome/base/feature_list_unittest.cc
@@ -0,0 +1,471 @@
+// 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/feature_list.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <utility>
+
+#include "base/format_macros.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const char kFeatureOnByDefaultName[] = "OnByDefault";
+struct Feature kFeatureOnByDefault {
+  kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
+};
+
+const char kFeatureOffByDefaultName[] = "OffByDefault";
+struct Feature kFeatureOffByDefault {
+  kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT
+};
+
+std::string SortFeatureListString(const std::string& feature_list) {
+  std::vector<std::string> features =
+      FeatureList::SplitFeatureListString(feature_list);
+  std::sort(features.begin(), features.end());
+  return JoinString(features, ",");
+}
+
+}  // namespace
+
+class FeatureListTest : public testing::Test {
+ public:
+  FeatureListTest() : feature_list_(nullptr) {
+    RegisterFeatureListInstance(WrapUnique(new FeatureList));
+  }
+  ~FeatureListTest() override { ClearFeatureListInstance(); }
+
+  void RegisterFeatureListInstance(std::unique_ptr<FeatureList> feature_list) {
+    FeatureList::ClearInstanceForTesting();
+    feature_list_ = feature_list.get();
+    FeatureList::SetInstance(std::move(feature_list));
+  }
+  void ClearFeatureListInstance() {
+    FeatureList::ClearInstanceForTesting();
+    feature_list_ = nullptr;
+  }
+
+  FeatureList* feature_list() { return feature_list_; }
+
+ private:
+  // Weak. Owned by the FeatureList::SetInstance().
+  FeatureList* feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(FeatureListTest);
+};
+
+TEST_F(FeatureListTest, DefaultStates) {
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+}
+
+TEST_F(FeatureListTest, InitializeFromCommandLine) {
+  struct {
+    const char* enable_features;
+    const char* disable_features;
+    bool expected_feature_on_state;
+    bool expected_feature_off_state;
+  } test_cases[] = {
+      {"", "", true, false},
+      {"OffByDefault", "", true, true},
+      {"OffByDefault", "OnByDefault", false, true},
+      {"OnByDefault,OffByDefault", "", true, true},
+      {"", "OnByDefault,OffByDefault", false, false},
+      // In the case an entry is both, disable takes precedence.
+      {"OnByDefault", "OnByDefault,OffByDefault", false, false},
+  };
+
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    const auto& test_case = test_cases[i];
+    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
+                                    test_case.enable_features,
+                                    test_case.disable_features));
+
+    ClearFeatureListInstance();
+    std::unique_ptr<FeatureList> feature_list(new FeatureList);
+    feature_list->InitializeFromCommandLine(test_case.enable_features,
+                                            test_case.disable_features);
+    RegisterFeatureListInstance(std::move(feature_list));
+
+    EXPECT_EQ(test_case.expected_feature_on_state,
+              FeatureList::IsEnabled(kFeatureOnByDefault))
+        << i;
+    EXPECT_EQ(test_case.expected_feature_off_state,
+              FeatureList::IsEnabled(kFeatureOffByDefault))
+        << i;
+  }
+}
+
+TEST_F(FeatureListTest, CheckFeatureIdentity) {
+  // Tests that CheckFeatureIdentity() correctly detects when two different
+  // structs with the same feature name are passed to it.
+
+  // Call it twice for each feature at the top of the file, since the first call
+  // makes it remember the entry and the second call will verify it.
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault));
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault));
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault));
+  EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault));
+
+  // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which
+  // should return false.
+  struct Feature kFeatureOnByDefault2 {
+    kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
+  };
+  EXPECT_FALSE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault2));
+}
+
+TEST_F(FeatureListTest, FieldTrialOverrides) {
+  struct {
+    FeatureList::OverrideState trial1_state;
+    FeatureList::OverrideState trial2_state;
+  } test_cases[] = {
+      {FeatureList::OVERRIDE_DISABLE_FEATURE,
+       FeatureList::OVERRIDE_DISABLE_FEATURE},
+      {FeatureList::OVERRIDE_DISABLE_FEATURE,
+       FeatureList::OVERRIDE_ENABLE_FEATURE},
+      {FeatureList::OVERRIDE_ENABLE_FEATURE,
+       FeatureList::OVERRIDE_DISABLE_FEATURE},
+      {FeatureList::OVERRIDE_ENABLE_FEATURE,
+       FeatureList::OVERRIDE_ENABLE_FEATURE},
+  };
+
+  FieldTrial::ActiveGroup active_group;
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    const auto& test_case = test_cases[i];
+    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));
+
+    ClearFeatureListInstance();
+
+    FieldTrialList field_trial_list(nullptr);
+    std::unique_ptr<FeatureList> feature_list(new FeatureList);
+
+    FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
+    FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
+    feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName,
+                                             test_case.trial1_state, trial1);
+    feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
+                                             test_case.trial2_state, trial2);
+    RegisterFeatureListInstance(std::move(feature_list));
+
+    // Initially, neither trial should be active.
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+
+    const bool expected_enabled_1 =
+        (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
+    EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault));
+    // The above should have activated |trial1|.
+    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+
+    const bool expected_enabled_2 =
+        (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
+    EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault));
+    // The above should have activated |trial2|.
+    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+  }
+}
+
+TEST_F(FeatureListTest, FieldTrialAssociateUseDefault) {
+  FieldTrialList field_trial_list(nullptr);
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+
+  FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
+  FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  // Initially, neither trial should be active.
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+
+  // Check the feature enabled state is its default.
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  // The above should have activated |trial1|.
+  EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+
+  // Check the feature enabled state is its default.
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  // The above should have activated |trial2|.
+  EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
+  EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
+}
+
+TEST_F(FeatureListTest, CommandLineTakesPrecedenceOverFieldTrial) {
+  ClearFeatureListInstance();
+
+  FieldTrialList field_trial_list(nullptr);
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+
+  // The feature is explicitly enabled on the command-line.
+  feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
+
+  // But the FieldTrial would set the feature to disabled.
+  FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
+  // Command-line should take precedence.
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  // Since the feature is on due to the command-line, and not as a result of the
+  // field trial, the field trial should not be activated (since the Associate*
+  // API wasn't used.)
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
+}
+
+TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
+  ClearFeatureListInstance();
+
+  FieldTrialList field_trial_list(nullptr);
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+
+  // No features are overridden from the command line yet
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+
+  // Now, enable |kFeatureOffByDefaultName| via the command-line.
+  feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");
+
+  // It should now be overridden for the enabled group.
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+
+  // Register a field trial to associate with the feature and ensure that the
+  // results are still the same.
+  feature_list->AssociateReportingFieldTrial(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
+      FieldTrialList::CreateFieldTrial("Trial1", "A"));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+
+  // Now, register a field trial to override |kFeatureOnByDefaultName| state
+  // and check that the function still returns false for that feature.
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
+      FieldTrialList::CreateFieldTrial("Trial2", "A"));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
+  EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  // Check the expected feature states for good measure.
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
+}
+
+TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
+  struct {
+    const char* enable_features;
+    const char* disable_features;
+    bool expected_enable_trial_created;
+    bool expected_disable_trial_created;
+  } test_cases[] = {
+      // If no enable/disable flags are specified, no trials should be created.
+      {"", "", false, false},
+      // Enabling the feature should result in the enable trial created.
+      {kFeatureOffByDefaultName, "", true, false},
+      // Disabling the feature should result in the disable trial created.
+      {"", kFeatureOffByDefaultName, false, true},
+  };
+
+  const char kTrialName[] = "ForcingTrial";
+  const char kForcedOnGroupName[] = "ForcedOn";
+  const char kForcedOffGroupName[] = "ForcedOff";
+
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    const auto& test_case = test_cases[i];
+    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
+                                    test_case.enable_features,
+                                    test_case.disable_features));
+
+    ClearFeatureListInstance();
+
+    FieldTrialList field_trial_list(nullptr);
+    std::unique_ptr<FeatureList> feature_list(new FeatureList);
+    feature_list->InitializeFromCommandLine(test_case.enable_features,
+                                            test_case.disable_features);
+
+    FieldTrial* enable_trial = nullptr;
+    if (feature_list->IsFeatureOverriddenFromCommandLine(
+            kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
+      enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
+                                                            kForcedOnGroupName);
+      feature_list->AssociateReportingFieldTrial(
+          kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
+          enable_trial);
+    }
+    FieldTrial* disable_trial = nullptr;
+    if (feature_list->IsFeatureOverriddenFromCommandLine(
+            kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) {
+      disable_trial = base::FieldTrialList::CreateFieldTrial(
+          kTrialName, kForcedOffGroupName);
+      feature_list->AssociateReportingFieldTrial(
+          kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
+          disable_trial);
+    }
+    EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
+    EXPECT_EQ(test_case.expected_disable_trial_created,
+              disable_trial != nullptr);
+    RegisterFeatureListInstance(std::move(feature_list));
+
+    EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+    if (disable_trial) {
+      EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+      EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
+      EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name());
+    } else if (enable_trial) {
+      EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+      EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
+      EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
+    }
+  }
+}
+
+TEST_F(FeatureListTest, GetFeatureOverrides) {
+  ClearFeatureListInstance();
+  FieldTrialList field_trial_list(nullptr);
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+  feature_list->InitializeFromCommandLine("A,X", "D");
+
+  FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
+  feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
+                                           FeatureList::OVERRIDE_ENABLE_FEATURE,
+                                           trial);
+
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  std::string enable_features;
+  std::string disable_features;
+  FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
+                                                  &disable_features);
+  EXPECT_EQ("A,OffByDefault<Trial,X", SortFeatureListString(enable_features));
+  EXPECT_EQ("D", SortFeatureListString(disable_features));
+}
+
+TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault) {
+  ClearFeatureListInstance();
+  FieldTrialList field_trial_list(nullptr);
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+  feature_list->InitializeFromCommandLine("A,X", "D");
+
+  FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
+
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  std::string enable_features;
+  std::string disable_features;
+  FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
+                                                  &disable_features);
+  EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features));
+  EXPECT_EQ("D", SortFeatureListString(disable_features));
+}
+
+TEST_F(FeatureListTest, GetFieldTrial) {
+  ClearFeatureListInstance();
+  FieldTrialList field_trial_list(nullptr);
+  FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+  feature_list->RegisterFieldTrialOverride(
+      kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
+  EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
+}
+
+TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) {
+  ClearFeatureListInstance();
+  FieldTrialList field_trial_list(nullptr);
+  FieldTrialList::CreateFieldTrial("Trial", "Group");
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+  feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
+}
+
+TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault) {
+  ClearFeatureListInstance();
+  FieldTrialList field_trial_list(nullptr);
+  FieldTrialList::CreateFieldTrial("T1", "Group");
+  FieldTrialList::CreateFieldTrial("T2", "Group");
+  std::unique_ptr<FeatureList> feature_list(new FeatureList);
+  feature_list->InitializeFromCommandLine(
+      "A,*OffByDefault<T1,*OnByDefault<T2,X", "D");
+  RegisterFeatureListInstance(std::move(feature_list));
+
+  EXPECT_FALSE(FieldTrialList::IsTrialActive("T1"));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+  EXPECT_TRUE(FieldTrialList::IsTrialActive("T1"));
+
+  EXPECT_FALSE(FieldTrialList::IsTrialActive("T2"));
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_TRUE(FieldTrialList::IsTrialActive("T2"));
+}
+
+TEST_F(FeatureListTest, InitializeInstance) {
+  ClearFeatureListInstance();
+
+  std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  FeatureList::SetInstance(std::move(feature_list));
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+
+  // Initialize from command line if we haven't yet.
+  FeatureList::InitializeInstance("", kFeatureOnByDefaultName);
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+
+  // Do not initialize from commandline if we have already.
+  FeatureList::InitializeInstance(kFeatureOffByDefaultName, "");
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+}
+
+TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse) {
+  ClearFeatureListInstance();
+  // This test case simulates the calling pattern found in code which does not
+  // explicitly initialize the features list.
+  // All IsEnabled() calls should return the default value in this scenario.
+  EXPECT_EQ(nullptr, FeatureList::GetInstance());
+  EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
+  EXPECT_EQ(nullptr, FeatureList::GetInstance());
+  EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
+}
+
+}  // namespace base
diff --git a/libchrome/base/file_descriptor_posix.h b/libchrome/base/file_descriptor_posix.h
new file mode 100644
index 0000000..2a36611
--- /dev/null
+++ b/libchrome/base/file_descriptor_posix.h
@@ -0,0 +1,59 @@
+// 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.
+//
+// IMPORTANT: This is primarily intended for use when sending file descriptors
+// over IPC. Even if |auto_close| is true, base::FileDescriptor does NOT close()
+// |fd| when going out of scope. Instead, a consumer of a base::FileDescriptor
+// must invoke close() on |fd| if |auto_close| is true.
+//
+// In the case of IPC, the the IPC subsystem knows to close() |fd| after sending
+// a message that contains a base::FileDescriptor if auto_close == true. On the
+// other end, the receiver must make sure to close() |fd| after it has finished
+// processing the IPC message. See the IPC::ParamTraits<> specialization in
+// ipc/ipc_message_utils.h for all the details.
+// -----------------------------------------------------------------------------
+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/libchrome/base/file_version_info.h b/libchrome/base/file_version_info.h
new file mode 100644
index 0000000..3b9457c
--- /dev/null
+++ b/libchrome/base/file_version_info.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_FILE_VERSION_INFO_H_
+#define BASE_FILE_VERSION_INFO_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+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);
+#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/libchrome/base/file_version_info_unittest.cc b/libchrome/base/file_version_info_unittest.cc
new file mode 100644
index 0000000..67edc77
--- /dev/null
+++ b/libchrome/base/file_version_info_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/file_version_info.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/path_service.h"
+#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 kDLLName[] = {L"FileVersionInfoTest1.dll"};
+
+  const wchar_t* const kExpectedValues[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
+  };
+
+  FilePath dll_path = GetTestDataPath();
+  dll_path = dll_path.Append(kDLLName);
+
+  std::unique_ptr<FileVersionInfo> version_info(
+      FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+  int j = 0;
+  EXPECT_EQ(kExpectedValues[j++], version_info->company_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->company_short_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_short_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->internal_name());
+  EXPECT_EQ(kExpectedValues[j++], version_info->product_version());
+  EXPECT_EQ(kExpectedValues[j++], version_info->private_build());
+  EXPECT_EQ(kExpectedValues[j++], version_info->special_build());
+  EXPECT_EQ(kExpectedValues[j++], version_info->comments());
+  EXPECT_EQ(kExpectedValues[j++], version_info->original_filename());
+  EXPECT_EQ(kExpectedValues[j++], version_info->file_description());
+  EXPECT_EQ(kExpectedValues[j++], version_info->file_version());
+  EXPECT_EQ(kExpectedValues[j++], version_info->legal_copyright());
+  EXPECT_EQ(kExpectedValues[j++], version_info->legal_trademarks());
+  EXPECT_EQ(kExpectedValues[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 (size_t i = 0; i < arraysize(kDLLNames); ++i) {
+    FilePath dll_path = GetTestDataPath();
+    dll_path = dll_path.Append(kDLLNames[i]);
+
+    std::unique_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");
+
+  std::unique_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/libchrome/base/files/dir_reader_fallback.h b/libchrome/base/files/dir_reader_fallback.h
new file mode 100644
index 0000000..4bc199a
--- /dev/null
+++ b/libchrome/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 nullptr;}
+
+  // 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/libchrome/base/files/dir_reader_linux.h b/libchrome/base/files/dir_reader_linux.h
new file mode 100644
index 0000000..4ce0c34
--- /dev/null
+++ b/libchrome/base/files/dir_reader_linux.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.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 nullptr;
+
+    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_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_DIR_READER_LINUX_H_
diff --git a/libchrome/base/files/dir_reader_posix.h b/libchrome/base/files/dir_reader_posix.h
new file mode 100644
index 0000000..6a32d9f
--- /dev/null
+++ b/libchrome/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/libchrome/base/files/dir_reader_posix_unittest.cc b/libchrome/base/files/dir_reader_posix_unittest.cc
new file mode 100644
index 0000000..a75858f
--- /dev/null
+++ b/libchrome/base/files/dir_reader_posix_unittest.cc
@@ -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.
+
+#include "base/files/dir_reader_posix.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "build/build_config.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;
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const char* dir = temp_dir.path().value().c_str();
+  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/libchrome/base/files/file.cc b/libchrome/base/files/file.cc
new file mode 100644
index 0000000..ab05630
--- /dev/null
+++ b/libchrome/base/files/file.cc
@@ -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.
+
+#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"
+#include "build/build_config.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_t 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(File&& other)
+    : file_(other.TakePlatformFile()),
+      tracing_path_(other.tracing_path_),
+      error_details_(other.error_details()),
+      created_(other.created()),
+      async_(other.async_) {}
+
+File::~File() {
+  // Go through the AssertIOAllowed logic.
+  Close();
+}
+
+// static
+File File::CreateForAsyncHandle(PlatformFile platform_file) {
+  File file(platform_file);
+  // It would be nice if we could validate that |platform_file| was opened with
+  // FILE_FLAG_OVERLAPPED on Windows but this doesn't appear to be possible.
+  file.async_ = true;
+  return file;
+}
+
+File& File::operator=(File&& other) {
+  DCHECK_NE(this, &other);
+  Close();
+  SetPlatformFile(other.TakePlatformFile());
+  tracing_path_ = other.tracing_path_;
+  error_details_ = other.error_details();
+  created_ = other.created();
+  async_ = other.async_;
+  return *this;
+}
+
+#if !defined(OS_NACL)
+void File::Initialize(const FilePath& path, uint32_t flags) {
+  if (path.ReferencesParent()) {
+    error_details_ = FILE_ERROR_ACCESS_DENIED;
+    return;
+  }
+  if (FileTracing::IsCategoryEnabled())
+    tracing_path_ = path;
+  SCOPED_FILE_TRACE("Initialize");
+  DoInitialize(path, 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/libchrome/base/files/file.h b/libchrome/base/files/file.h
new file mode 100644
index 0000000..ae2bd1b
--- /dev/null
+++ b/libchrome/base/files/file.h
@@ -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.
+
+#ifndef BASE_FILES_FILE_H_
+#define BASE_FILES_FILE_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/files/file_tracing.h"
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include "base/win/scoped_handle.h"
+#endif
+
+#if defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
+namespace base {
+
+#if defined(OS_WIN)
+using PlatformFile = HANDLE;
+
+const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE;
+#elif defined(OS_POSIX)
+using PlatformFile = int;
+
+const PlatformFile kInvalidPlatformFile = -1;
+#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 {
+ 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.
+    FLAG_SEQUENTIAL_SCAN = 1 << 19,   // 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_t 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_t 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);
+
+  File(File&& other);
+
+  ~File();
+
+  // Takes ownership of |platform_file|.
+  static File CreateForAsyncHandle(PlatformFile platform_file);
+
+  File& operator=(File&& other);
+
+  // Creates or opens the given file.
+  void Initialize(const FilePath& path, uint32_t flags);
+
+  // Returns |true| if the handle / fd wrapped by this object is valid.  This
+  // method doesn't interact with the file system (and is safe to be called from
+  // ThreadRestrictions::SetIOAllowed(false) threads).
+  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_t Seek(Whence whence, int64_t 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_t 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_t 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_t 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_t 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_t 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 class FileTracing::ScopedTrace;
+
+  // Creates or opens the given file. Only called if |path| has no
+  // traversal ('..') components.
+  void DoInitialize(const FilePath& path, uint32_t 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)
+  ScopedFD file_;
+#endif
+
+  // A path to use for tracing purposes. Set if file tracing is enabled during
+  // |Initialize()|.
+  FilePath tracing_path_;
+
+  // Object tied to the lifetime of |this| that enables/disables tracing.
+  FileTracing::ScopedEnabler trace_enabler_;
+
+  Error error_details_;
+  bool created_;
+  bool async_;
+
+  DISALLOW_COPY_AND_ASSIGN(File);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_H_
+
diff --git a/libchrome/base/files/file_enumerator.cc b/libchrome/base/files/file_enumerator.cc
new file mode 100644
index 0000000..9749980
--- /dev/null
+++ b/libchrome/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/libchrome/base/files/file_enumerator.h b/libchrome/base/files/file_enumerator.h
new file mode 100644
index 0000000..7cac8dd
--- /dev/null
+++ b/libchrome/base/files/file_enumerator.h
@@ -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.
+
+#ifndef BASE_FILES_FILE_ENUMERATOR_H_
+#define BASE_FILES_FILE_ENUMERATOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <stack>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/macros.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_t 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/libchrome/base/files/file_enumerator_posix.cc b/libchrome/base/files/file_enumerator_posix.cc
new file mode 100644
index 0000000..fb4010a
--- /dev/null
+++ b/libchrome/base/files/file_enumerator_posix.cc
@@ -0,0 +1,162 @@
+// 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 <stdint.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.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_t 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/libchrome/base/files/file_path.cc b/libchrome/base/files/file_path.cc
new file mode 100644
index 0000000..29f12a8
--- /dev/null
+++ b/libchrome/base/files/file_path.cc
@@ -0,0 +1,1339 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/logging.h"
+#include "base/macros.h"
+#include "base/pickle.h"
+#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"
+#include "build/build_config.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 {
+
+using StringType = FilePath::StringType;
+using StringPieceType = FilePath::StringPieceType;
+
+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.
+StringPieceType::size_type FindDriveLetter(StringPieceType 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;
+  }
+#else
+  (void)path;  // Avoid an unused warning.
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+  return StringType::npos;
+}
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+bool EqualDriveLetterCaseInsensitive(StringPieceType a, StringPieceType 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;
+
+  StringPieceType a_letter(a.substr(0, a_letter_pos + 1));
+  StringPieceType b_letter(b.substr(0, b_letter_pos + 1));
+  if (!StartsWith(a_letter, b_letter, CompareCase::INSENSITIVE_ASCII))
+    return false;
+
+  StringPieceType a_rest(a.substr(a_letter_pos + 1));
+  StringPieceType b_rest(b.substr(b_letter_pos + 1));
+  return a_rest == b_rest;
+}
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+bool IsPathAbsolute(StringPieceType 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(StringPieceType path) {
+  path.CopyToString(&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, CompareCase::INSENSITIVE_ASCII))
+      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(StringPieceType suffix) const {
+  if (suffix.empty())
+    return FilePath(path_);
+
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  StringType ext = Extension();
+  StringType ret = RemoveExtension().value();
+  suffix.AppendToString(&ret);
+  ret.append(ext);
+  return FilePath(ret);
+}
+
+FilePath FilePath::InsertBeforeExtensionASCII(StringPiece suffix)
+    const {
+  DCHECK(IsStringASCII(suffix));
+#if defined(OS_WIN)
+  return InsertBeforeExtension(ASCIIToUTF16(suffix));
+#elif defined(OS_POSIX)
+  return InsertBeforeExtension(suffix);
+#endif
+}
+
+FilePath FilePath::AddExtension(StringPieceType extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  // If the new extension is "" or ".", then just return the current FilePath.
+  if (extension.empty() ||
+      (extension.size() == 1 && extension[0] == kExtensionSeparator))
+    return *this;
+
+  StringType str = path_;
+  if (extension[0] != kExtensionSeparator &&
+      *(str.end() - 1) != kExtensionSeparator) {
+    str.append(1, kExtensionSeparator);
+  }
+  extension.AppendToString(&str);
+  return FilePath(str);
+}
+
+FilePath FilePath::ReplaceExtension(StringPieceType 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.size() == 1 && extension[0] == kExtensionSeparator))
+    return no_ext;
+
+  StringType str = no_ext.value();
+  if (extension[0] != kExtensionSeparator)
+    str.append(1, kExtensionSeparator);
+  extension.AppendToString(&str);
+  return FilePath(str);
+}
+
+bool FilePath::MatchesExtension(StringPieceType 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(StringPieceType component) const {
+  StringPieceType appended = component;
+  StringType without_nuls;
+
+  StringType::size_type nul_pos = component.find(kStringTerminator);
+  if (nul_pos != StringPieceType::npos) {
+    component.substr(0, nul_pos).CopyToString(&without_nuls);
+    appended = StringPieceType(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.empty() && !new_path.path_.empty()) {
+    // 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_.back())) {
+      // 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]);
+      }
+    }
+  }
+
+  appended.AppendToString(&new_path.path_);
+  return new_path;
+}
+
+FilePath FilePath::Append(const FilePath& component) const {
+  return Append(component.value());
+}
+
+FilePath FilePath::AppendASCII(StringPiece component) const {
+  DCHECK(base::IsStringASCII(component));
+#if defined(OS_WIN)
+  return Append(ASCIIToUTF16(component));
+#elif defined(OS_POSIX)
+  return Append(component);
+#endif
+}
+
+bool FilePath::IsAbsolute() const {
+  return IsPathAbsolute(path_);
+}
+
+bool FilePath::EndsWithSeparator() const {
+  if (empty())
+    return false;
+  return IsSeparator(path_.back());
+}
+
+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(StringPiece utf8) {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return FilePath(utf8);
+#else
+  return FilePath(SysWideToNativeMB(UTF8ToWide(utf8)));
+#endif
+}
+
+// static
+FilePath FilePath::FromUTF16Unsafe(StringPiece16 utf16) {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return FilePath(UTF16ToUTF8(utf16));
+#else
+  return FilePath(SysWideToNativeMB(UTF16ToWide(utf16.as_string())));
+#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(StringPiece utf8) {
+  return FilePath(UTF8ToWide(utf8));
+}
+
+// static
+FilePath FilePath::FromUTF16Unsafe(StringPiece16 utf16) {
+  return FilePath(utf16);
+}
+#endif
+
+void FilePath::GetSizeForPickle(PickleSizer* sizer) const {
+#if defined(OS_WIN)
+  sizer->AddString16(path_);
+#else
+  sizer->AddString(path_);
+#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(StringPieceType string1,
+                                StringPieceType string2) {
+  static decltype(::CharUpperW)* const char_upper_api =
+      reinterpret_cast<decltype(::CharUpperW)*>(
+          ::GetProcAddress(::GetModuleHandle(L"user32.dll"), "CharUpperW"));
+  CHECK(char_upper_api);
+  // 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
+  StringPieceType::const_iterator i1 = string1.begin();
+  StringPieceType::const_iterator i2 = string2.begin();
+  StringPieceType::const_iterator string1end = string1.end();
+  StringPieceType::const_iterator string2end = string2.end();
+  for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
+    wchar_t c1 =
+        (wchar_t)LOWORD(char_upper_api((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0)));
+    wchar_t c2 =
+        (wchar_t)LOWORD(char_upper_api((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;
+}
+
+}  // 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(StringPieceType string1,
+                                    StringPieceType string2) {
+  int length1 = string1.length();
+  int length2 = string2.length();
+  int index1 = 0;
+  int index2 = 0;
+
+  for (;;) {
+    int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.data(),
+                                                      length1,
+                                                      &index1);
+    int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.data(),
+                                                      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(StringPieceType string) {
+  StringType result;
+  ScopedCFTypeRef<CFStringRef> cfstring(
+      CFStringCreateWithBytesNoCopy(
+          NULL,
+          reinterpret_cast<const UInt8*>(string.data()),
+          string.length(),
+          kCFStringEncodingUTF8,
+          false,
+          kCFAllocatorNull));
+  if (cfstring) {
+    // 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!)
+    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(StringPieceType string1,
+                                StringPieceType 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.data()),
+            string1.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    ScopedCFTypeRef<CFStringRef> cfstring2(
+        CFStringCreateWithBytesNoCopy(
+            NULL,
+            reinterpret_cast<const UInt8*>(string2.data()),
+            string2.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    return CFStringCompare(cfstring1,
+                           cfstring2,
+                           kCFCompareCaseInsensitive);
+  }
+
+  return HFSFastUnicodeCompare(hfs1, hfs2);
+}
+
+#else  // << WIN. MACOSX | other (POSIX) >>
+
+// Generic Posix system comparisons.
+int FilePath::CompareIgnoreCase(StringPieceType string1,
+                                StringPieceType string2) {
+  // Specifically need null termianted strings for this API call.
+  int comparison = strcasecmp(string1.as_string().c_str(),
+                              string2.as_string().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
+  (void)separator;  // Avoid an unused warning.
+  return *this;
+#endif
+}
+
+#if defined(OS_ANDROID)
+bool FilePath::IsContentUri() const {
+  return StartsWith(path_, "content://", base::CompareCase::INSENSITIVE_ASCII);
+}
+#endif
+
+}  // namespace base
diff --git a/libchrome/base/files/file_path.h b/libchrome/base/files/file_path.h
new file mode 100644
index 0000000..3234df7
--- /dev/null
+++ b/libchrome/base/files/file_path.h
@@ -0,0 +1,479 @@
+// Copyright (c) 2012 The Chromium 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/macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#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
+
+// To print path names portably use PRIsFP (based on PRIuS and friends from
+// C99 and format_macros.h) like this:
+// base::StringPrintf("Path is %" PRIsFP ".\n", path.value().c_str());
+#if defined(OS_POSIX)
+#define PRIsFP "s"
+#elif defined(OS_WIN)
+#define PRIsFP "ls"
+#endif  // OS_WIN
+
+namespace base {
+
+class Pickle;
+class PickleIterator;
+class PickleSizer;
+
+// 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 BasicStringPiece<StringType> StringPieceType;
+  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(StringPieceType 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(
+      StringPieceType suffix) const WARN_UNUSED_RESULT;
+  FilePath InsertBeforeExtensionASCII(
+      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(StringPieceType 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(StringPieceType 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(StringPieceType 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(StringPieceType 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(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(StringPiece utf8);
+
+  // Similar to FromUTF8Unsafe, but accepts UTF-16 instead.
+  static FilePath FromUTF16Unsafe(StringPiece16 utf16);
+
+  void GetSizeForPickle(PickleSizer* sizer) const;
+  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(StringPieceType string1,
+                               StringPieceType string2);
+  static bool CompareEqualIgnoreCase(StringPieceType string1,
+                                     StringPieceType string2) {
+    return CompareIgnoreCase(string1, string2) == 0;
+  }
+  static bool CompareLessIgnoreCase(StringPieceType string1,
+                                    StringPieceType 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(StringPieceType 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(StringPieceType string1,
+                                   StringPieceType 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/libchrome/base/files/file_path_constants.cc b/libchrome/base/files/file_path_constants.cc
new file mode 100644
index 0000000..0b74846
--- /dev/null
+++ b/libchrome/base/files/file_path_constants.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 <stddef.h>
+
+#include "base/files/file_path.h"
+#include "base/macros.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/libchrome/base/files/file_path_unittest.cc b/libchrome/base/files/file_path_unittest.cc
new file mode 100644
index 0000000..d8c5969
--- /dev/null
+++ b/libchrome/base/files/file_path_unittest.cc
@@ -0,0 +1,1318 @@
+// Copyright (c) 2012 The Chromium Authors. 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 <sstream>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_locale.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if defined(OS_POSIX)
+#include "base/test/scoped_locale.h"
+#endif
+
+// 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" },
+  };
+
+#if !defined(SYSTEM_NATIVE_UTF8) && defined(OS_LINUX)
+  ScopedLocale locale("en_US.UTF-8");
+#endif
+
+  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());
+}
+
+// Test GetHFSDecomposedForm should return empty result for invalid UTF-8
+// strings.
+#if defined(OS_MACOSX)
+TEST_F(FilePathTest, GetHFSDecomposedFormWithInvalidInput) {
+  const FilePath::CharType* cases[] = {
+    FPL("\xc3\x28"),
+    FPL("\xe2\x82\x28"),
+    FPL("\xe2\x28\xa1"),
+    FPL("\xf0\x28\x8c\xbc"),
+    FPL("\xf0\x28\x8c\x28"),
+  };
+  for (const auto& invalid_input : cases) {
+    FilePath::StringType observed = FilePath::GetHFSDecomposedForm(
+        invalid_input);
+    EXPECT_TRUE(observed.empty());
+  }
+}
+#endif
+
+}  // namespace base
diff --git a/libchrome/base/files/file_path_watcher.cc b/libchrome/base/files/file_path_watcher.cc
new file mode 100644
index 0000000..a4624ab
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher.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.
+
+// 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"
+#include "build/build_config.h"
+
+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)) || defined(OS_WIN) || \
+    defined(OS_LINUX) || defined(OS_ANDROID)
+  return true;
+#else
+  // FSEvents isn't available on iOS.
+  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/libchrome/base/files/file_path_watcher.h b/libchrome/base/files/file_path_watcher.h
new file mode 100644
index 0000000..d5c6db1
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher.h
@@ -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.
+
+// 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/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.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> runner) {
+      task_runner_ = std::move(runner);
+    }
+
+    // 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/libchrome/base/files/file_path_watcher_fsevents.cc b/libchrome/base/files/file_path_watcher_fsevents.cc
new file mode 100644
index 0000000..e9d2508
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher_fsevents.cc
@@ -0,0 +1,276 @@
+// 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 <dispatch/dispatch.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/scoped_cftyperef.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace base {
+
+namespace {
+
+// The latency parameter passed to FSEventsStreamCreate().
+const CFAbsoluteTime kEventLatencySeconds = 0.3;
+
+// 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()
+    : queue_(dispatch_queue_create(
+          base::StringPrintf(
+              "org.chromium.base.FilePathWatcher.%p", this).c_str(),
+          DISPATCH_QUEUE_SERIAL)),
+      fsevent_stream_(nullptr) {
+}
+
+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();
+  // The block runtime would implicitly capture the reference, not the object
+  // it's referencing. Copy the path into a local, so that the value is
+  // captured by the block's scope.
+  const FilePath path_copy(path);
+
+  dispatch_async(queue_, ^{
+      StartEventStream(start_event, path_copy);
+  });
+  return true;
+}
+
+void FilePathWatcherFSEvents::Cancel() {
+  set_cancelled();
+  callback_.Reset();
+
+  // Switch to the dispatch queue to tear down the event stream. As the queue
+  // is owned by this object, and this method is called from the destructor,
+  // execute the block synchronously.
+  dispatch_sync(queue_, ^{
+      CancelOnMessageLoopThread();
+  });
+}
+
+// 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);
+  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.
+    dispatch_async(watcher->queue_, ^{
+        watcher->UpdateEventStream(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(!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.
+
+  if (fsevent_stream_) {
+    DestroyEventStream();
+    target_.clear();
+    resolved_target_.clear();
+  }
+}
+
+void FilePathWatcherFSEvents::UpdateEventStream(
+    FSEventStreamEventId start_event) {
+  // 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_, queue_);
+
+  if (!FSEventStreamStart(fsevent_stream_)) {
+    task_runner()->PostTask(
+        FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
+  }
+}
+
+bool FilePathWatcherFSEvents::ResolveTargetPath() {
+  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(resolved_target_.empty());
+
+  target_ = path;
+  ResolveTargetPath();
+  UpdateEventStream(start_event);
+}
+
+}  // namespace base
diff --git a/libchrome/base/files/file_path_watcher_fsevents.h b/libchrome/base/files/file_path_watcher_fsevents.h
new file mode 100644
index 0000000..cfbe020
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher_fsevents.h
@@ -0,0 +1,100 @@
+// 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 <stddef.h>
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+#include "base/mac/scoped_dispatch_object.h"
+#include "base/macros.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_;
+
+  // The dispatch queue on which the the event stream is scheduled.
+  ScopedDispatchObject<dispatch_queue_t> queue_;
+
+  // Target path to watch (passed to callback).
+  // (Only accessed from the libdispatch queue.)
+  FilePath target_;
+
+  // Target path with all symbolic links resolved.
+  // (Only accessed from the libdispatch queue.)
+  FilePath resolved_target_;
+
+  // Backend stream we receive event callbacks from (strong reference).
+  // (Only accessed from the libdispatch queue.)
+  FSEventStreamRef fsevent_stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherFSEvents);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
diff --git a/libchrome/base/files/file_path_watcher_kqueue.cc b/libchrome/base/files/file_path_watcher_kqueue.cc
new file mode 100644
index 0000000..6d034cd
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher_kqueue.cc
@@ -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/files/file_path_watcher_kqueue.h"
+
+#include <fcntl.h>
+#include <stddef.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/threading/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/libchrome/base/files/file_path_watcher_kqueue.h b/libchrome/base/files/file_path_watcher_kqueue.h
new file mode 100644
index 0000000..d9db8c2
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher_kqueue.h
@@ -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.
+
+#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/macros.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/libchrome/base/files/file_path_watcher_linux.cc b/libchrome/base/files/file_path_watcher_linux.cc
new file mode 100644
index 0000000..87bddd3
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher_linux.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 "base/files/file_path_watcher.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#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/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.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. Update |watch_entry| on success.
+  void 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("/"));
+  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();
+    watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
+    if (watch_entry.watch == InotifyReader::kInvalidWatch) {
+      // Ignore the error code (beyond symlink handling) to attempt to add
+      // watches on accessible children of unreadable directories. Note that
+      // this is a best-effort attempt; we may not catch events in this
+      // scenario.
+      if (IsLink(path))
+        AddWatchForBrokenSymlink(path, &watch_entry);
+    }
+    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();
+}
+
+void FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
+                                                   WatchEntry* watch_entry) {
+  DCHECK_EQ(InotifyReader::kInvalidWatch, watch_entry->watch);
+  FilePath link;
+  if (!ReadSymbolicLink(path, &link))
+    return;
+
+  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;
+  }
+  watch_entry->watch = watch;
+  watch_entry->linkname = link.BaseName().value();
+}
+
+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_.back().subdir.empty();
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/libchrome/base/files/file_path_watcher_mac.cc b/libchrome/base/files/file_path_watcher_mac.cc
new file mode 100644
index 0000000..7338eaf
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher_mac.cc
@@ -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.
+
+#include "base/files/file_path_watcher.h"
+#include "base/files/file_path_watcher_kqueue.h"
+#include "build/build_config.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/libchrome/base/files/file_path_watcher_unittest.cc b/libchrome/base/files/file_path_watcher_unittest.cc
new file mode 100644
index 0000000..a40e485
--- /dev/null
+++ b/libchrome/base/files/file_path_watcher_unittest.cc
@@ -0,0 +1,914 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/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/macros.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/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.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();
+    // Make sure we timeout if we don't get notified.
+    loop_.PostDelayedTask(FROM_HERE,
+                          MessageLoop::QuitWhenIdleClosure(),
+                          TestTimeouts::action_timeout());
+    RunLoop().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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                 WaitableEvent::InitialState::NOT_SIGNALED);
+  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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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:
+  std::unique_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.
+  std::unique_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) {
+  std::unique_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;
+  std::unique_ptr<TestDelegate> delegate1(new TestDelegate(collector()));
+  std::unique_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"));
+  std::unique_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"));
+  std::unique_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"));
+  std::unique_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;
+  std::unique_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"));
+  std::unique_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"));
+  std::unique_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get(), false));
+  std::unique_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"));
+  std::unique_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"));
+  std::unique_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"));
+
+  std::unique_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get(), false));
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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"));
+  std::unique_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"));
+  std::unique_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"));
+  std::unique_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;
+  std::unique_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_.task_runner()->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/libchrome/base/files/file_posix.cc b/libchrome/base/files/file_posix.cc
new file mode 100644
index 0000000..12f80c4
--- /dev/null
+++ b/libchrome/base/files/file_posix.cc
@@ -0,0 +1,535 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.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"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+// Make sure our Whence mappings match the system headers.
+static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR &&
+                  File::FROM_END == SEEK_END,
+              "whence mapping must match the system headers");
+
+namespace {
+
+#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+int CallFstat(int fd, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return fstat(fd, sb);
+}
+#else
+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)
+bool IsOpenAppend(PlatformFile file) {
+  return (fcntl(file, F_GETFL) & O_APPEND) != 0;
+}
+
+int CallFtruncate(PlatformFile file, int64_t length) {
+  return HANDLE_EINTR(ftruncate(file, length));
+}
+
+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
+}
+
+File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
+  struct flock lock;
+  lock.l_type = do_lock ? F_WRLCK : F_UNLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = 0;
+  lock.l_len = 0;  // Lock entire file.
+  if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1)
+    return File::OSErrorToFileError(errno);
+  return File::FILE_OK;
+}
+#else  // defined(OS_NACL)
+
+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;
+}
+
+int CallFtruncate(PlatformFile file, int64_t length) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement ftruncate.
+  return 0;
+}
+
+int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement futimes.
+  return 0;
+}
+
+File::Error CallFcntlFlock(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_t last_modified_nsec = stat_info.st_mtim.tv_nsec;
+  time_t last_accessed_sec = stat_info.st_atim.tv_sec;
+  int64_t last_accessed_nsec = stat_info.st_atim.tv_nsec;
+  time_t creation_time_sec = stat_info.st_ctim.tv_sec;
+  int64_t creation_time_nsec = stat_info.st_ctim.tv_nsec;
+#elif defined(OS_ANDROID)
+  time_t last_modified_sec = stat_info.st_mtime;
+  int64_t last_modified_nsec = stat_info.st_mtime_nsec;
+  time_t last_accessed_sec = stat_info.st_atime;
+  int64_t last_accessed_nsec = stat_info.st_atime_nsec;
+  time_t creation_time_sec = stat_info.st_ctime;
+  int64_t 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_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
+  time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
+  int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
+  time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
+  int64_t creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
+#else
+  time_t last_modified_sec = stat_info.st_mtime;
+  int64_t last_modified_nsec = 0;
+  time_t last_accessed_sec = stat_info.st_atime;
+  int64_t last_accessed_nsec = 0;
+  time_t creation_time_sec = stat_info.st_ctime;
+  int64_t 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_t File::Seek(Whence whence, int64_t offset) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
+
+// Additionally check __BIONIC__ since older versions of Android don't define
+// _FILE_OFFSET_BITS.
+#if _FILE_OFFSET_BITS != 64 || defined(__BIONIC__)
+  static_assert(sizeof(int64_t) == sizeof(off64_t), "off64_t must be 64 bits");
+  return lseek64(file_.get(), static_cast<off64_t>(offset),
+                 static_cast<int>(whence));
+#else
+  static_assert(sizeof(int64_t) == sizeof(off_t), "off_t must be 64 bits");
+  return lseek(file_.get(), static_cast<off_t>(offset),
+               static_cast<int>(whence));
+#endif
+}
+
+int File::Read(int64_t 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_t 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_t 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_t 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_t 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 CallFcntlFlock(file_.get(), true);
+}
+
+File::Error File::Unlock() {
+  SCOPED_FILE_TRACE("Unlock");
+  return CallFcntlFlock(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;
+}
+
+// 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;
+  }
+}
+
+// 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(const FilePath& path, uint32_t 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;
+
+  static_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/libchrome/base/files/file_tracing.cc b/libchrome/base/files/file_tracing.cc
new file mode 100644
index 0000000..6d11cbc
--- /dev/null
+++ b/libchrome/base/files/file_tracing.cc
@@ -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.
+
+#include "base/files/file_tracing.h"
+
+#include "base/files/file.h"
+
+namespace base {
+
+namespace {
+FileTracing::Provider* g_provider = nullptr;
+}
+
+// static
+bool FileTracing::IsCategoryEnabled() {
+  return g_provider && g_provider->FileTracingCategoryIsEnabled();
+}
+
+// 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_);
+}
+
+void FileTracing::ScopedTrace::Initialize(const char* name,
+                                          File* file,
+                                          int64_t size) {
+  id_ = &file->trace_enabler_;
+  name_ = name;
+  g_provider->FileTracingEventBegin(name_, id_, file->tracing_path_, size);
+}
+
+}  // namespace base
diff --git a/libchrome/base/files/file_tracing.h b/libchrome/base/files/file_tracing.h
new file mode 100644
index 0000000..bedd7be
--- /dev/null
+++ b/libchrome/base/files/file_tracing.h
@@ -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.
+
+#ifndef BASE_FILES_FILE_TRACING_H_
+#define BASE_FILES_FILE_TRACING_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+#define FILE_TRACING_PREFIX "File"
+
+#define SCOPED_FILE_TRACE_WITH_SIZE(name, size) \
+    FileTracing::ScopedTrace scoped_file_trace; \
+    if (FileTracing::IsCategoryEnabled()) \
+      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:
+  // Whether the file tracing category is enabled.
+  static bool IsCategoryEnabled();
+
+  class Provider {
+   public:
+    virtual ~Provider() = default;
+
+    // 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_t 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();
+
+    // 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_t 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/libchrome/base/files/file_unittest.cc b/libchrome/base/files/file_unittest.cc
new file mode 100644
index 0000000..2445f7e
--- /dev/null
+++ b/libchrome/base/files/file_unittest.cc
@@ -0,0 +1,517 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.h>
+
+#include <utility>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/time/time.h"
+#include "build/build_config.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_t 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 = std::move(file2);
+  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_t 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_t 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(),
+                   GENERIC_READ | GENERIC_WRITE,
+                   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)
diff --git a/libchrome/base/files/file_util.cc b/libchrome/base/files/file_util.cc
new file mode 100644
index 0000000..80fa44f
--- /dev/null
+++ b/libchrome/base/files/file_util.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2012 The Chromium Authors. All 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"
+#include "build/build_config.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_t ComputeDirectorySize(const FilePath& root_path) {
+  int64_t 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 ReadFileToStringWithMaxSize(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;
+  std::unique_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 ReadFileToStringWithMaxSize(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_t* 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/libchrome/base/files/file_util.h b/libchrome/base/files/file_util.h
new file mode 100644
index 0000000..420dcae
--- /dev/null
+++ b/libchrome/base/files/file_util.h
@@ -0,0 +1,450 @@
+// Copyright (c) 2012 The Chromium 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/strings/string16.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
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#endif
+
+namespace base {
+
+class Environment;
+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_t 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 ReadFileToStringWithMaxSize(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);
+
+// Returns true iff |executable| can be found in any directory specified by the
+// environment variable in |env|.
+BASE_EXPORT bool ExecutableExistsInPath(Environment* env,
+                                        const FilePath::StringType& executable);
+
+#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_t* 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);
+
+// Given an existing file in |path|, returns whether this file is on a network
+// drive or not. If |path| does not exist, this function returns false.
+BASE_EXPORT bool IsOnNetworkDrive(const base::FilePath& 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);
+
+// Sets the given |fd| to non-blocking mode.
+// Returns true if it was able to set it in the non-blocking mode, otherwise
+// false.
+BASE_EXPORT bool SetNonBlocking(int fd);
+
+#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/libchrome/base/files/file_util_linux.cc b/libchrome/base/files/file_util_linux.cc
new file mode 100644
index 0000000..b0c6e03
--- /dev/null
+++ b/libchrome/base/files/file_util_linux.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/files/file_util.h"
+
+#include <errno.h>
+#include <linux/magic.h>
+#include <stdint.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.
+  // In some platforms, |statfs_buf.f_type| is declared as signed, but some of
+  // the values will overflow it, causing narrowing warnings. Cast to the
+  // largest possible unsigned integer type to avoid it.
+  switch (static_cast<uintmax_t>(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/libchrome/base/files/file_util_mac.mm b/libchrome/base/files/file_util_mac.mm
new file mode 100644
index 0000000..e9c6c65
--- /dev/null
+++ b/libchrome/base/files/file_util_mac.mm
@@ -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.
+
+#include "base/files/file_util.h"
+
+#include <copyfile.h>
+#import <Foundation/Foundation.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/libchrome/base/files/file_util_posix.cc b/libchrome/base/files/file_util_posix.cc
new file mode 100644
index 0000000..85a1b41
--- /dev/null
+++ b/libchrome/base/files/file_util_posix.cc
@@ -0,0 +1,960 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.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>
+
+#include "base/environment.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/macros.h"
+#include "base/memory/singleton.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.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"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#include "base/mac/foundation_util.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/android/content_uri_utils.h"
+#include "base/os_compat_android.h"
+#include "base/path_service.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 SetNonBlocking(int fd) {
+  const int flags = fcntl(fd, F_GETFL);
+  if (flags == -1)
+    return false;
+  if (flags & O_NONBLOCK)
+    return true;
+  if (HANDLE_EINTR(fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1)
+    return false;
+  return true;
+}
+
+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;
+}
+
+bool ExecutableExistsInPath(Environment* env,
+                            const FilePath::StringType& executable) {
+  std::string path;
+  if (!env->GetVar("PATH", &path)) {
+    LOG(ERROR) << "No $PATH variable. Assuming no " << executable << ".";
+    return false;
+  }
+
+  for (const StringPiece& cur_path :
+       SplitStringPiece(path, ":", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+    FilePath file(cur_path);
+    int permissions;
+    if (GetPosixFilePermissions(file.Append(executable), &permissions) &&
+        (permissions & FILE_PERMISSION_EXECUTE_BY_USER))
+      return true;
+  }
+  return false;
+}
+
+#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);
+#elif defined(__ANDROID__)
+    *path = FilePath("/data/local/tmp");
+#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.";
+#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(), 0666));
+  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;
+  }
+#else
+  (void)executable;  // Avoid unused warning when !defined(OS_LINUX).
+#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/libchrome/base/files/important_file_writer.cc b/libchrome/base/files/important_file_writer.cc
new file mode 100644
index 0000000..28550ad
--- /dev/null
+++ b/libchrome/base/files/important_file_writer.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 "base/files/important_file_writer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+#include <utility>
+
+#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/macros.h"
+#include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.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"
+#include "build/build_config.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,
+                StringPiece message) {
+  UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code,
+                            TEMP_FILE_FAILURE_MAX);
+  DPLOG(WARNING) << "temp file failure: " << path.value() << " : " << message;
+}
+
+// Helper function to call WriteFileAtomically() with a
+// std::unique_ptr<std::string>.
+bool WriteScopedStringToFileAtomically(const FilePath& path,
+                                       std::unique_ptr<std::string> data) {
+  return ImportantFileWriter::WriteFileAtomically(path, *data);
+}
+
+}  // namespace
+
+// static
+bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
+                                              StringPiece 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();
+  strlcpy(file_info.path, path.value().c_str(), arraysize(file_info.path));
+  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 (!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 fails in the wild, something really bad is going on.
+  const int data_length = checked_cast<int32_t>(data.length());
+  int bytes_written = tmp_file.Write(0, data.data(), data_length);
+  bool flush_success = tmp_file.Flush();
+  tmp_file.Close();
+
+  if (bytes_written < data_length) {
+    LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
+               IntToString(bytes_written));
+    DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  if (!flush_success) {
+    LogFailure(path, FAILED_FLUSHING, "error flushing");
+    DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  if (!ReplaceFile(tmp_file_path, path, nullptr)) {
+    LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
+    DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  return true;
+}
+
+ImportantFileWriter::ImportantFileWriter(
+    const FilePath& path,
+    scoped_refptr<SequencedTaskRunner> task_runner)
+    : ImportantFileWriter(
+          path,
+          std::move(task_runner),
+          TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)) {}
+
+ImportantFileWriter::ImportantFileWriter(
+    const FilePath& path,
+    scoped_refptr<SequencedTaskRunner> task_runner,
+    TimeDelta interval)
+    : path_(path),
+      task_runner_(std::move(task_runner)),
+      serializer_(nullptr),
+      commit_interval_(interval),
+      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(std::unique_ptr<std::string> data) {
+  DCHECK(CalledOnValidThread());
+  if (!IsValueInRangeForNumericType<int32_t>(data->length())) {
+    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_);
+  std::unique_ptr<std::string> data(new std::string);
+  if (serializer_->SerializeData(data.get())) {
+    WriteNow(std::move(data));
+  } else {
+    DLOG(WARNING) << "failed to serialize data to be saved in "
+                  << path_.value();
+  }
+  serializer_ = nullptr;
+}
+
+void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback(
+    const 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 PostTaskAndReplyWithResult(
+        task_runner_.get(),
+        FROM_HERE,
+        MakeCriticalClosure(task),
+        Bind(&ImportantFileWriter::ForwardSuccessfulWrite,
+             weak_factory_.GetWeakPtr()));
+  }
+  return task_runner_->PostTask(
+      FROM_HERE,
+      MakeCriticalClosure(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/libchrome/base/files/important_file_writer.h b/libchrome/base/files/important_file_writer.h
new file mode 100644
index 0000000..0bd8a7f
--- /dev/null
+++ b/libchrome/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/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.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://blog.valerieaurora.org/2009/04/16/dont-panic-fsync-ext34-and-your-data/
+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, StringPiece 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,
+                      scoped_refptr<SequencedTaskRunner> task_runner);
+
+  // Same as above, but with a custom commit interval.
+  ImportantFileWriter(const FilePath& path,
+                      scoped_refptr<SequencedTaskRunner> task_runner,
+                      TimeDelta interval);
+
+  // 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(std::unique_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 Closure& on_next_successful_write);
+
+  TimeDelta commit_interval() const {
+    return commit_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.
+  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<SequencedTaskRunner> task_runner_;
+
+  // Timer used to schedule commit after ScheduleWrite.
+  OneShotTimer timer_;
+
+  // Serializer which will provide the data to be saved.
+  DataSerializer* serializer_;
+
+  // Time delta after which scheduled data will be written to disk.
+  const TimeDelta commit_interval_;
+
+  WeakPtrFactory<ImportantFileWriter> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_IMPORTANT_FILE_WRITER_H_
diff --git a/libchrome/base/files/important_file_writer_unittest.cc b/libchrome/base/files/important_file_writer_unittest.cc
new file mode 100644
index 0000000..43e051e
--- /dev/null
+++ b/libchrome/base/files/important_file_writer_unittest.cc
@@ -0,0 +1,198 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.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(WrapUnique(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(WrapUnique(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(WrapUnique(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(WrapUnique(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(),
+                             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));
+  RunLoop().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));
+  RunLoop().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(),
+                             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));
+  RunLoop().Run();
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("baz", GetFileContent(writer.path()));
+}
+
+}  // namespace base
diff --git a/libchrome/base/files/memory_mapped_file.cc b/libchrome/base/files/memory_mapped_file.cc
new file mode 100644
index 0000000..67890d6
--- /dev/null
+++ b/libchrome/base/files/memory_mapped_file.cc
@@ -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.
+
+#include "base/files/memory_mapped_file.h"
+
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/sys_info.h"
+#include "build/build_config.h"
+
+namespace base {
+
+const MemoryMappedFile::Region MemoryMappedFile::Region::kWholeFile = {0, 0};
+
+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, Access access) {
+  if (IsValid())
+    return false;
+
+  uint32_t flags = 0;
+  switch (access) {
+    case READ_ONLY:
+      flags = File::FLAG_OPEN | File::FLAG_READ;
+      break;
+    case READ_WRITE:
+      flags = File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE;
+      break;
+    case READ_WRITE_EXTEND:
+      // Can't open with "extend" because no maximum size is known.
+      NOTREACHED();
+  }
+  file_.Initialize(file_name, flags);
+
+  if (!file_.IsValid()) {
+    DLOG(ERROR) << "Couldn't open " << file_name.AsUTF8Unsafe();
+    return false;
+  }
+
+  if (!MapFileRegionToMemory(Region::kWholeFile, access)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::Initialize(File file, Access access) {
+  DCHECK_NE(READ_WRITE_EXTEND, access);
+  return Initialize(std::move(file), Region::kWholeFile, access);
+}
+
+bool MemoryMappedFile::Initialize(File file,
+                                  const Region& region,
+                                  Access access) {
+  switch (access) {
+    case READ_WRITE_EXTEND:
+      // Ensure that the extended size is within limits of File.
+      if (region.size > std::numeric_limits<int64_t>::max() - region.offset) {
+        DLOG(ERROR) << "Region bounds exceed maximum for base::File.";
+        return false;
+      }
+      // Fall through.
+    case READ_ONLY:
+    case READ_WRITE:
+      // Ensure that the region values are valid.
+      if (region.offset < 0 || region.size < 0) {
+        DLOG(ERROR) << "Region bounds are not valid.";
+        return false;
+      }
+      break;
+  }
+
+  if (IsValid())
+    return false;
+
+  if (region != Region::kWholeFile) {
+    DCHECK_GE(region.offset, 0);
+    DCHECK_GT(region.size, 0);
+  }
+
+  file_ = std::move(file);
+
+  if (!MapFileRegionToMemory(region, access)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::IsValid() const {
+  return data_ != NULL;
+}
+
+// static
+void MemoryMappedFile::CalculateVMAlignedBoundaries(int64_t start,
+                                                    int64_t size,
+                                                    int64_t* aligned_start,
+                                                    int64_t* aligned_size,
+                                                    int32_t* offset) {
+  // Sadly, on Windows, the mmap alignment is not just equal to the page size.
+  const int64_t mask =
+      static_cast<int64_t>(SysInfo::VMAllocationGranularity()) - 1;
+  DCHECK_LT(mask, std::numeric_limits<int32_t>::max());
+  *offset = start & mask;
+  *aligned_start = start & ~mask;
+  *aligned_size = (size + *offset + mask) & ~mask;
+}
+#endif
+
+}  // namespace base
diff --git a/libchrome/base/files/memory_mapped_file.h b/libchrome/base/files/memory_mapped_file.h
new file mode 100644
index 0000000..cad99f6
--- /dev/null
+++ b/libchrome/base/files/memory_mapped_file.h
@@ -0,0 +1,136 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+class FilePath;
+
+class BASE_EXPORT MemoryMappedFile {
+ public:
+  enum Access {
+    // Mapping a file into memory effectively allows for file I/O on any thread.
+    // The accessing thread could be paused while data from the file is paged
+    // into memory. Worse, a corrupted filesystem could cause a SEGV within the
+    // program instead of just an I/O error.
+    READ_ONLY,
+
+    // This provides read/write access to a file and must be used with care of
+    // the additional subtleties involved in doing so. Though the OS will do
+    // the writing of data on its own time, too many dirty pages can cause
+    // the OS to pause the thread while it writes them out. The pause can
+    // be as much as 1s on some systems.
+    READ_WRITE,
+
+    // This provides read/write access but with the ability to write beyond
+    // the end of the existing file up to a maximum size specified as the
+    // "region". Depending on the OS, the file may or may not be immediately
+    // extended to the maximum size though it won't be loaded in RAM until
+    // needed. Note, however, that the maximum size will still be reserved
+    // in the process address space.
+    READ_WRITE_EXTEND,
+  };
+
+  // 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;
+
+    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_t offset;
+
+    // Length of the region in bytes.
+    int64_t size;
+  };
+
+  // Opens an existing file and maps it into memory. |access| can be read-only
+  // or read/write but not read/write+extend. 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.
+  bool Initialize(const FilePath& file_name, Access access);
+  bool Initialize(const FilePath& file_name) {
+    return Initialize(file_name, READ_ONLY);
+  }
+
+  // As above, but works with an already-opened file. |access| can be read-only
+  // or read/write but not read/write+extend. MemoryMappedFile takes ownership
+  // of |file| and closes it when done. |file| must have been opened with
+  // permissions suitable for |access|. If the memory mapping fails, it will
+  // return false.
+  bool Initialize(File file, Access access);
+  bool Initialize(File file) {
+    return Initialize(std::move(file), READ_ONLY);
+  }
+
+  // As above, but works with a region of an already-opened file. All forms of
+  // |access| are allowed. If READ_WRITE_EXTEND is specified then |region|
+  // provides the maximum size of the file. If the memory mapping fails, it
+  // return false.
+  bool Initialize(File file, const Region& region, Access access);
+  bool Initialize(File file, const Region& region) {
+    return Initialize(std::move(file), region, READ_ONLY);
+  }
+
+  const uint8_t* data() const { return data_; }
+  uint8_t* data() { 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_t start,
+                                           int64_t size,
+                                           int64_t* aligned_start,
+                                           int64_t* aligned_size,
+                                           int32_t* 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, Access access);
+
+  // Closes all open handles.
+  void CloseHandles();
+
+  File file_;
+  uint8_t* data_;
+  size_t length_;
+
+#if defined(OS_WIN)
+  win::ScopedHandle file_mapping_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_MEMORY_MAPPED_FILE_H_
diff --git a/libchrome/base/files/memory_mapped_file_posix.cc b/libchrome/base/files/memory_mapped_file_posix.cc
new file mode 100644
index 0000000..4899cf0
--- /dev/null
+++ b/libchrome/base/files/memory_mapped_file_posix.cc
@@ -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.
+
+#include "base/files/memory_mapped_file.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+
+namespace base {
+
+MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) {
+}
+
+#if !defined(OS_NACL)
+bool MemoryMappedFile::MapFileRegionToMemory(
+    const MemoryMappedFile::Region& region,
+    Access access) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  off_t map_start = 0;
+  size_t map_size = 0;
+  int32_t data_offset = 0;
+
+  if (region == MemoryMappedFile::Region::kWholeFile) {
+    int64_t 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_t aligned_start = 0;
+    int64_t 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_t>(aligned_size) >
+            std::numeric_limits<size_t>::max() ||
+        static_cast<uint64_t>(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);
+  }
+
+  int flags = 0;
+  switch (access) {
+    case READ_ONLY:
+      flags |= PROT_READ;
+      break;
+    case READ_WRITE:
+      flags |= PROT_READ | PROT_WRITE;
+      break;
+    case READ_WRITE_EXTEND:
+      // POSIX won't auto-extend the file when it is written so it must first
+      // be explicitly extended to the maximum size. Zeros will fill the new
+      // space.
+      file_.SetLength(std::max(file_.GetLength(), region.offset + region.size));
+      flags |= PROT_READ | PROT_WRITE;
+      break;
+  }
+  data_ = static_cast<uint8_t*>(mmap(NULL, map_size, flags, 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/libchrome/base/files/scoped_file.cc b/libchrome/base/files/scoped_file.cc
new file mode 100644
index 0000000..8ce45b8
--- /dev/null
+++ b/libchrome/base/files/scoped_file.cc
@@ -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.
+
+#include "base/files/scoped_file.h"
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <unistd.h>
+
+#include "base/debug/alias.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.
+  int ret = IGNORE_EINTR(close(fd));
+
+  // TODO(davidben): Remove this once it's been determined whether
+  // https://crbug.com/603354 is caused by EBADF or a network filesystem
+  // returning some other error.
+  int close_errno = errno;
+  base::debug::Alias(&close_errno);
+
+  PCHECK(0 == ret);
+}
+
+#endif  // OS_POSIX
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/files/scoped_file.h b/libchrome/base/files/scoped_file.h
new file mode 100644
index 0000000..68c0415
--- /dev/null
+++ b/libchrome/base/files/scoped_file.h
@@ -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.
+
+#ifndef BASE_FILES_SCOPED_FILE_H_
+#define BASE_FILES_SCOPED_FILE_H_
+
+#include <stdio.h>
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/logging.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 std::unique_ptr<FILE, internal::ScopedFILECloser> ScopedFILE;
+
+}  // namespace base
+
+#endif  // BASE_FILES_SCOPED_FILE_H_
diff --git a/libchrome/base/files/scoped_temp_dir.cc b/libchrome/base/files/scoped_temp_dir.cc
new file mode 100644
index 0000000..27b758e
--- /dev/null
+++ b/libchrome/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/libchrome/base/files/scoped_temp_dir.h b/libchrome/base/files/scoped_temp_dir.h
new file mode 100644
index 0000000..b1f2f5b
--- /dev/null
+++ b/libchrome/base/files/scoped_temp_dir.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.
+
+#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"
+#include "base/macros.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/libchrome/base/files/scoped_temp_dir_unittest.cc b/libchrome/base/files/scoped_temp_dir_unittest.cc
new file mode 100644
index 0000000..3b2f28e
--- /dev/null
+++ b/libchrome/base/files/scoped_temp_dir_unittest.cc
@@ -0,0 +1,114 @@
+// 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 "build/build_config.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/libchrome/base/format_macros.h b/libchrome/base/format_macros.h
new file mode 100644
index 0000000..0697c6d
--- /dev/null
+++ b/libchrome/base/format_macros.h
@@ -0,0 +1,97 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#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/libchrome/base/gmock_unittest.cc b/libchrome/base/gmock_unittest.cc
new file mode 100644
index 0000000..855380a
--- /dev/null
+++ b/libchrome/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/libchrome/base/gtest_prod_util.h b/libchrome/base/gtest_prod_util.h
new file mode 100644
index 0000000..3289e63
--- /dev/null
+++ b/libchrome/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/libchrome/base/guid.cc b/libchrome/base/guid.cc
new file mode 100644
index 0000000..5714073
--- /dev/null
+++ b/libchrome/base/guid.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/guid.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/rand_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+namespace {
+
+bool IsLowerHexDigit(char c) {
+  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
+}
+
+bool IsValidGUIDInternal(const base::StringPiece& guid, bool strict) {
+  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 ((strict && !IsLowerHexDigit(current)) || !IsHexDigit(current))
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
+std::string GenerateGUID() {
+  uint64_t 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);
+}
+
+bool IsValidGUID(const base::StringPiece& guid) {
+  return IsValidGUIDInternal(guid, false /* strict */);
+}
+
+bool IsValidGUIDOutputString(const base::StringPiece& guid) {
+  return IsValidGUIDInternal(guid, true /* strict */);
+}
+
+std::string RandomDataToGUIDString(const uint64_t 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/libchrome/base/guid.h b/libchrome/base/guid.h
new file mode 100644
index 0000000..29c24ea
--- /dev/null
+++ b/libchrome/base/guid.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_GUID_H_
+#define BASE_GUID_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Generate a 128-bit (pseudo) random GUID in the form of 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].
+// The hexadecimal values "a" through "f" are output as lower case characters.
+// If GUID generation fails an empty string is returned.
+BASE_EXPORT std::string GenerateGUID();
+
+// Returns true if the input string conforms to the version 4 GUID format.
+// Note that this does NOT check if the hexadecimal values "a" through "f"
+// are in lower case characters, as Version 4 RFC says onput they're
+// case insensitive. (Use IsValidGUIDOutputString for checking if the
+// given string is valid output string)
+BASE_EXPORT bool IsValidGUID(const base::StringPiece& guid);
+
+// Returns true if the input string is valid version 4 GUID output string.
+// This also checks if the hexadecimal values "a" through "f" are in lower
+// case characters.
+BASE_EXPORT bool IsValidGUIDOutputString(const base::StringPiece& guid);
+
+// For unit testing purposes only.  Do not use outside of tests.
+BASE_EXPORT std::string RandomDataToGUIDString(const uint64_t bytes[2]);
+
+}  // namespace base
+
+#endif  // BASE_GUID_H_
diff --git a/libchrome/base/guid_unittest.cc b/libchrome/base/guid_unittest.cc
new file mode 100644
index 0000000..70dad67
--- /dev/null
+++ b/libchrome/base/guid_unittest.cc
@@ -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.
+
+#include "base/guid.h"
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+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_t bytes[] = {0, 0};
+  std::string clientid = RandomDataToGUIDString(bytes);
+  EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
+}
+
+TEST(GUIDTest, GUIDGeneratesCorrectly) {
+  uint64_t bytes[] = {0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL};
+  std::string clientid = RandomDataToGUIDString(bytes);
+  EXPECT_EQ("01234567-89ab-cdef-fedc-ba9876543210", clientid);
+}
+
+TEST(GUIDTest, GUIDCorrectlyFormatted) {
+  const int kIterations = 10;
+  for (int it = 0; it < kIterations; ++it) {
+    std::string guid = GenerateGUID();
+    EXPECT_TRUE(IsValidGUID(guid));
+    EXPECT_TRUE(IsValidGUIDOutputString(guid));
+    EXPECT_TRUE(IsValidGUID(ToLowerASCII(guid)));
+    EXPECT_TRUE(IsValidGUID(ToUpperASCII(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);
+    EXPECT_TRUE(IsGUIDv4(guid1));
+    EXPECT_TRUE(IsGUIDv4(guid2));
+  }
+}
+
+}  // namespace base
diff --git a/libchrome/base/hash.cc b/libchrome/base/hash.cc
new file mode 100644
index 0000000..4dfd0d0
--- /dev/null
+++ b/libchrome/base/hash.cc
@@ -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.
+
+#include "base/hash.h"
+
+#include <functional>
+
+namespace base {
+
+uint32_t SuperFastHash(const char* data, size_t len) {
+  std::hash<std::string> hash_fn;
+  return hash_fn(std::string(data, len));
+}
+
+}  // namespace base
diff --git a/libchrome/base/hash.h b/libchrome/base/hash.h
new file mode 100644
index 0000000..7c0fba6
--- /dev/null
+++ b/libchrome/base/hash.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_HASH_H_
+#define BASE_HASH_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <string>
+#include <utility>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+
+namespace base {
+
+// WARNING: This hash function should not be used for any cryptographic purpose.
+BASE_EXPORT uint32_t SuperFastHash(const char* data, size_t length);
+
+// 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_t Hash(const char* data, size_t length) {
+  return SuperFastHash(data, length);
+}
+
+// Computes a hash of a string |str|.
+// WARNING: This hash function should not be used for any cryptographic purpose.
+inline uint32_t Hash(const std::string& str) {
+  return Hash(str.data(), str.size());
+}
+
+// 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 size_t HashInts32(uint32_t value1, uint32_t value2) {
+  uint64_t value1_64 = value1;
+  uint64_t hash64 = (value1_64 << 32) | value2;
+
+  if (sizeof(size_t) >= sizeof(uint64_t))
+    return static_cast<size_t>(hash64);
+
+  uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
+  uint32_t shift_random = 10121U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  size_t high_bits =
+      static_cast<size_t>(hash64 >> (8 * (sizeof(uint64_t) - sizeof(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 size_t HashInts64(uint64_t value1, uint64_t value2) {
+  uint32_t short_random1 = 842304669U;
+  uint32_t short_random2 = 619063811U;
+  uint32_t short_random3 = 937041849U;
+  uint32_t short_random4 = 3309708029U;
+
+  uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
+  uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
+  uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
+  uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
+
+  uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
+  uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
+  uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
+  uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
+
+  uint64_t hash64 = product1 + product2 + product3 + product4;
+
+  if (sizeof(size_t) >= sizeof(uint64_t))
+    return static_cast<size_t>(hash64);
+
+  uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
+  uint32_t shift_random = 20591U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  size_t high_bits =
+      static_cast<size_t>(hash64 >> (8 * (sizeof(uint64_t) - sizeof(size_t))));
+  return high_bits;
+}
+
+template <typename T1, typename T2>
+inline size_t HashInts(T1 value1, T2 value2) {
+  // This condition is expected to be compile-time evaluated and optimised away
+  // in release builds.
+  if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
+    return HashInts64(value1, value2);
+
+  return HashInts32(value1, value2);
+}
+
+// A templated hasher for pairs of integer types.
+template <typename T>
+struct IntPairHash;
+
+template <typename Type1, typename Type2>
+struct IntPairHash<std::pair<Type1, Type2>> {
+  size_t operator()(std::pair<Type1, Type2> value) const {
+    return HashInts(value.first, value.second);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_HASH_H_
diff --git a/libchrome/base/i18n/OWNERS b/libchrome/base/i18n/OWNERS
new file mode 100644
index 0000000..d717b8d
--- /dev/null
+++ b/libchrome/base/i18n/OWNERS
@@ -0,0 +1 @@
+jshin@chromium.org
diff --git a/libchrome/base/i18n/base_i18n_export.h b/libchrome/base/i18n/base_i18n_export.h
new file mode 100644
index 0000000..e8a2add
--- /dev/null
+++ b/libchrome/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/libchrome/base/id_map.h b/libchrome/base/id_map.h
new file mode 100644
index 0000000..ef6b156
--- /dev/null
+++ b/libchrome/base/id_map.h
@@ -0,0 +1,285 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#include <set>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/sequence_checker.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,
+          typename K = int32_t>
+class IDMap {
+ public:
+  using KeyType = K;
+
+ 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 consistent, thread (or sequence)
+    // post-construction. The first call to CalledOnValidSequencedThread()
+    // will re-bind it.
+    sequence_checker_.DetachFromSequence();
+  }
+
+  ~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 (or
+    // sequence), such as the IO thread. Detaching again to clean this up.
+    sequence_checker_.DetachFromSequence();
+    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(sequence_checker_.CalledOnValidSequencedThread());
+    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(sequence_checker_.CalledOnValidSequencedThread());
+    DCHECK(!check_on_null_data_ || data);
+    DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
+    data_[id] = data;
+  }
+
+  void Remove(KeyType id) {
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+    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(sequence_checker_.CalledOnValidSequencedThread());
+    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(sequence_checker_.CalledOnValidSequencedThread());
+    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(sequence_checker_.CalledOnValidSequencedThread());
+    return size() == 0u;
+  }
+
+  T* Lookup(KeyType id) const {
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+    typename HashTable::const_iterator i = data_.find(id);
+    if (i == data_.end())
+      return NULL;
+    return i->second;
+  }
+
+  size_t size() const {
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+    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, K>* 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_->sequence_checker_.CalledOnValidSequencedThread());
+
+      // 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_->sequence_checker_.CalledOnValidSequencedThread());
+      return iter_ == map_->data_.end();
+    }
+
+    KeyType GetCurrentKey() const {
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
+      return iter_->first;
+    }
+
+    ReturnType* GetCurrentValue() const {
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
+      return iter_->second;
+    }
+
+    void Advance() {
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
+      ++iter_;
+      SkipRemovedEntries();
+    }
+
+   private:
+    void Init() {
+      DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
+      ++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, K>* 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 (const auto& i : removed_ids_)
+      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_;
+
+  base::SequenceChecker sequence_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(IDMap);
+};
+
+#endif  // BASE_ID_MAP_H_
diff --git a/libchrome/base/id_map_unittest.cc b/libchrome/base/id_map_unittest.cc
new file mode 100644
index 0000000..a3f0808
--- /dev/null
+++ b/libchrome/base/id_map_unittest.cc
@@ -0,0 +1,379 @@
+// 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 <stdint.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_t id1 = map.Add(&obj1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+
+  int32_t 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_t 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_t 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);
+}
+
+TEST(IDMapTest, Int64KeyType) {
+  IDMap<TestObject, IDMapExternalPointer, int64_t> map;
+  TestObject obj1;
+  const int64_t kId1 = 999999999999999999;
+
+  map.AddWithID(&obj1, kId1);
+  EXPECT_EQ(&obj1, map.Lookup(kId1));
+
+  IDMap<TestObject, IDMapExternalPointer, int64_t>::const_iterator iter(&map);
+  ASSERT_FALSE(iter.IsAtEnd());
+  EXPECT_EQ(kId1, iter.GetCurrentKey());
+  EXPECT_EQ(&obj1, iter.GetCurrentValue());
+  iter.Advance();
+  ASSERT_TRUE(iter.IsAtEnd());
+
+  map.Remove(kId1);
+  EXPECT_TRUE(map.IsEmpty());
+}
+
+}  // namespace
diff --git a/libchrome/base/ios/OWNERS b/libchrome/base/ios/OWNERS
new file mode 100644
index 0000000..06f5ff1
--- /dev/null
+++ b/libchrome/base/ios/OWNERS
@@ -0,0 +1,3 @@
+droger@chromium.org
+qsr@chromium.org
+rohitrao@chromium.org
diff --git a/libchrome/base/ios/block_types.h b/libchrome/base/ios/block_types.h
new file mode 100644
index 0000000..e4dde79
--- /dev/null
+++ b/libchrome/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/libchrome/base/json/json_file_value_serializer.cc b/libchrome/base/json/json_file_value_serializer.cc
new file mode 100644
index 0000000..1a9b7a2
--- /dev/null
+++ b/libchrome/base/json/json_file_value_serializer.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/json/json_file_value_serializer.h"
+
+#include "base/files/file_util.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "build/build_config.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 "";
+  }
+}
+
+std::unique_ptr<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/libchrome/base/json/json_file_value_serializer.h b/libchrome/base/json/json_file_value_serializer.h
new file mode 100644
index 0000000..67d2342
--- /dev/null
+++ b/libchrome/base/json/json_file_value_serializer.h
@@ -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.
+
+#ifndef BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+#define BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/macros.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.
+  std::unique_ptr<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/libchrome/base/json/json_parser.cc b/libchrome/base/json/json_parser.cc
new file mode 100644
index 0000000..d97eccc
--- /dev/null
+++ b/libchrome/base/json/json_parser.cc
@@ -0,0 +1,989 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.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_t kExtendedASCIIStart = 0x80;
+
+// DictionaryHiddenRootValue and ListHiddenRootValue are used in conjunction
+// with JSONStringValue as an optimization for reducing the number of string
+// copies. When this optimization is active, the parser uses a hidden root to
+// keep the original JSON input string live and creates JSONStringValue children
+// holding StringPiece references to the input string, avoiding about 2/3rds of
+// string memory copies. The real root value is Swap()ed into the new instance.
+class DictionaryHiddenRootValue : public DictionaryValue {
+ public:
+  DictionaryHiddenRootValue(std::unique_ptr<std::string> json,
+                            std::unique_ptr<Value> root)
+      : json_(std::move(json)) {
+    DCHECK(root->IsType(Value::TYPE_DICTIONARY));
+    DictionaryValue::Swap(static_cast<DictionaryValue*>(root.get()));
+  }
+
+  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|.
+    std::unique_ptr<DictionaryValue> copy(CreateDeepCopy());
+    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,
+                                  std::unique_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.
+    std::unique_ptr<Value> out_owned;
+    if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned))
+      return false;
+
+    *out = out_owned->CreateDeepCopy();
+
+    return true;
+  }
+
+ private:
+  std::unique_ptr<std::string> json_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue);
+};
+
+class ListHiddenRootValue : public ListValue {
+ public:
+  ListHiddenRootValue(std::unique_ptr<std::string> json,
+                      std::unique_ptr<Value> root)
+      : json_(std::move(json)) {
+    DCHECK(root->IsType(Value::TYPE_LIST));
+    ListValue::Swap(static_cast<ListValue*>(root.get()));
+  }
+
+  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|.
+    std::unique_ptr<ListValue> copy(CreateDeepCopy());
+    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, std::unique_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.
+    std::unique_ptr<Value> out_owned;
+    if (!ListValue::Remove(index, &out_owned))
+      return false;
+
+    *out = out_owned->CreateDeepCopy();
+
+    return true;
+  }
+
+ private:
+  std::unique_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 Value {
+ public:
+  explicit JSONStringValue(StringPiece piece)
+      : Value(TYPE_STRING), string_piece_(piece) {}
+
+  // Overridden from 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.
+  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_(nullptr),
+      pos_(nullptr),
+      end_pos_(nullptr),
+      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() {
+}
+
+std::unique_ptr<Value> JSONParser::Parse(StringPiece input) {
+  std::unique_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 = MakeUnique<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_t>(*pos_) == 0xEF &&
+      static_cast<uint8_t>(*(pos_ + 1)) == 0xBB &&
+      static_cast<uint8_t>(*(pos_ + 2)) == 0xBF) {
+    NextNChars(3);
+  }
+
+  // Parse the first and any nested tokens.
+  std::unique_ptr<Value> root(ParseNextToken());
+  if (!root)
+    return nullptr;
+
+  // 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 nullptr;
+    }
+  }
+
+  // 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 MakeUnique<DictionaryHiddenRootValue>(std::move(input_copy),
+                                                   std::move(root));
+    }
+    if (root->IsType(Value::TYPE_LIST)) {
+      return MakeUnique<ListHiddenRootValue>(std::move(input_copy),
+                                             std::move(root));
+    }
+    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->CreateDeepCopy();
+    }
+  }
+
+  // All other values can be returned directly.
+  return root;
+}
+
+JSONReader::JsonParseError JSONParser::error_code() const {
+  return error_code_;
+}
+
+std::string JSONParser::GetErrorMessage() const {
+  return FormatErrorMessage(error_line_, error_column_,
+      JSONReader::ErrorCodeToString(error_code_));
+}
+
+int JSONParser::error_line() const {
+  return error_line_;
+}
+
+int JSONParser::error_column() const {
+  return error_column_;
+}
+
+// StringBuilder ///////////////////////////////////////////////////////////////
+
+JSONParser::StringBuilder::StringBuilder() : StringBuilder(nullptr) {}
+
+JSONParser::StringBuilder::StringBuilder(const char* pos)
+    : pos_(pos),
+      length_(0),
+      string_(nullptr) {
+}
+
+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(static_cast<unsigned char>(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 nullptr;
+  }
+}
+
+Value* JSONParser::ConsumeDictionary() {
+  if (*pos_ != '{') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return nullptr;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return nullptr;
+  }
+
+  std::unique_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 nullptr;
+    }
+
+    // First consume the key.
+    StringBuilder key;
+    if (!ConsumeStringRaw(&key)) {
+      return nullptr;
+    }
+
+    // Read the separator.
+    NextChar();
+    token = GetNextToken();
+    if (token != T_OBJECT_PAIR_SEPARATOR) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return nullptr;
+    }
+
+    // The next token is the value. Ownership transfers to |dict|.
+    NextChar();
+    Value* value = ParseNextToken();
+    if (!value) {
+      // ReportError from deeper level.
+      return nullptr;
+    }
+
+    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 nullptr;
+      }
+    } else if (token != T_OBJECT_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+      return nullptr;
+    }
+  }
+
+  return dict.release();
+}
+
+Value* JSONParser::ConsumeList() {
+  if (*pos_ != '[') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return nullptr;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return nullptr;
+  }
+
+  std::unique_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 nullptr;
+    }
+
+    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 nullptr;
+      }
+    } else if (token != T_ARRAY_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return nullptr;
+    }
+  }
+
+  return list.release();
+}
+
+Value* JSONParser::ConsumeString() {
+  StringBuilder string;
+  if (!ConsumeStringRaw(&string))
+    return nullptr;
+
+  // 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());
+
+  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_t 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 (next_char == '"') {
+      --index_;  // Rewind by one because of CBU8_NEXT.
+      out->Swap(&string);
+      return true;
+    }
+
+    // If this character is not an escape sequence...
+    if (next_char != '\\') {
+      if (next_char < kExtendedASCIIStart)
+        string.Append(static_cast<char>(next_char));
+      else
+        DecodeUTF8(next_char, &string);
+    } else {
+      // And if it is an escape sequence, 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;
+      }
+    }
+  }
+
+  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_t code_point =
+        CBU16_GET_SUPPLEMENTARY(code_unit16_high, code_unit16_low);
+    if (!IsValidCharacter(code_point))
+      return false;
+
+    offset = 0;
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_point);
+  } else {
+    // Not a surrogate.
+    DCHECK(CBU16_IS_SINGLE(code_unit16_high));
+    if (!IsValidCharacter(code_unit16_high))
+      return false;
+
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high);
+  }
+
+  dest_string->append(code_unit8);
+  return true;
+}
+
+void JSONParser::DecodeUTF8(const int32_t& point, StringBuilder* dest) {
+  DCHECK(IsValidCharacter(point));
+
+  // Anything outside of the basic ASCII plane will need to be decoded from
+  // int32_t 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 nullptr;
+  }
+  end_index = index_;
+
+  // The optional fraction part.
+  if (*pos_ == '.') {
+    if (!CanConsume(1)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return nullptr;
+    }
+    NextChar();
+    if (!ReadInt(true)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return nullptr;
+    }
+    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 nullptr;
+    }
+    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 nullptr;
+  }
+
+  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 (StringToDouble(num_string.as_string(), &num_double) &&
+      std::isfinite(num_double)) {
+    return new FundamentalValue(num_double);
+  }
+
+  return nullptr;
+}
+
+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 nullptr;
+      }
+      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 nullptr;
+      }
+      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 nullptr;
+      }
+      NextNChars(kNullLen - 1);
+      return Value::CreateNullValue().release();
+    }
+    default:
+      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+      return nullptr;
+  }
+}
+
+// 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/libchrome/base/json/json_parser.h b/libchrome/base/json/json_parser.h
new file mode 100644
index 0000000..7539fa9
--- /dev/null
+++ b/libchrome/base/json/json_parser.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_JSON_JSON_PARSER_H_
+#define BASE_JSON_JSON_PARSER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+class Value;
+
+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 JSONParser {
+ public:
+  explicit JSONParser(int options);
+  ~JSONParser();
+
+  // Parses the input string according to the set options and returns the
+  // result as a Value.
+  // Wrap this in base::FooValue::From() to check the Value is of type Foo and
+  // convert to a FooValue at the same time.
+  std::unique_ptr<Value> Parse(StringPiece input);
+
+  // Returns the error code.
+  JSONReader::JsonParseError error_code() const;
+
+  // Returns the human-friendly error message.
+  std::string GetErrorMessage() const;
+
+  // Returns the error line number if parse error happened. Otherwise always
+  // returns 0.
+  int error_line() const;
+
+  // Returns the error column number if parse error happened. Otherwise always
+  // returns 0.
+  int error_column() 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. std::unique_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_t& 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.
+  const 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/libchrome/base/json/json_parser_unittest.cc b/libchrome/base/json/json_parser_unittest.cc
new file mode 100644
index 0000000..30255ca
--- /dev/null
+++ b/libchrome/base/json/json_parser_unittest.cc
@@ -0,0 +1,327 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <memory>
+
+#include "base/json/json_reader.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");
+  std::unique_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\",|");
+  std::unique_ptr<JSONParser> parser(NewTestParser(input));
+  std::unique_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],|");
+  std::unique_ptr<JSONParser> parser(NewTestParser(input));
+  std::unique_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\"},|");
+  std::unique_ptr<JSONParser> parser(NewTestParser(input));
+  std::unique_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,|");
+  std::unique_ptr<JSONParser> parser(NewTestParser(input));
+  std::unique_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,|");
+  std::unique_ptr<JSONParser> parser(NewTestParser(input));
+  std::unique_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;
+  std::unique_ptr<Value> root = JSONReader::ReadAndReturnError(
+      "[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 = JSONReader::ReadAndReturnError(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 = JSONReader::ReadAndReturnError(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 = JSONReader::ReadAndReturnError("{},{}", 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 = JSONReader::ReadAndReturnError(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 = JSONReader::ReadAndReturnError("[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 = JSONReader::ReadAndReturnError("{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 = JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", JSON_PARSE_RFC,
+                                        &error_code, &error_message);
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
+            error_message);
+
+  root = JSONReader::ReadAndReturnError("[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 = JSONReader::ReadAndReturnError("[\"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 = JSONReader::ReadAndReturnError("[\"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 = JSONReader::ReadAndReturnError("[\"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;
+  std::unique_ptr<Value> root = JSONReader::ReadAndReturnError(
+      kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message);
+  EXPECT_TRUE(root.get()) << error_message;
+}
+
+TEST_F(JSONParserTest, DecodeUnicodeNonCharacter) {
+  // Tests Unicode code points (encoded as escaped UTF-16) that are not valid
+  // characters.
+  EXPECT_FALSE(JSONReader::Read("[\"\\ufdd0\"]"));
+  EXPECT_FALSE(JSONReader::Read("[\"\\ufffe\"]"));
+  EXPECT_FALSE(JSONReader::Read("[\"\\ud83f\\udffe\"]"));
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/json/json_reader.cc b/libchrome/base/json/json_reader.cc
new file mode 100644
index 0000000..4ff7496
--- /dev/null
+++ b/libchrome/base/json/json_reader.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.
+static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
+              "JSONReader 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
+std::unique_ptr<Value> JSONReader::Read(StringPiece json) {
+  internal::JSONParser parser(JSON_PARSE_RFC);
+  return parser.Parse(json);
+}
+
+// static
+std::unique_ptr<Value> JSONReader::Read(StringPiece json, int options) {
+  internal::JSONParser parser(options);
+  return parser.Parse(json);
+}
+
+
+// static
+std::unique_ptr<Value> JSONReader::ReadAndReturnError(
+    const StringPiece& json,
+    int options,
+    int* error_code_out,
+    std::string* error_msg_out,
+    int* error_line_out,
+    int* error_column_out) {
+  internal::JSONParser parser(options);
+  std::unique_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();
+    if (error_line_out)
+      *error_line_out = parser.error_line();
+    if (error_column_out)
+      *error_column_out = parser.error_column();
+  }
+
+  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();
+  }
+}
+
+std::unique_ptr<Value> JSONReader::ReadToValue(StringPiece json) {
+  return 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/libchrome/base/json/json_reader.h b/libchrome/base/json/json_reader.h
new file mode 100644
index 0000000..a954821
--- /dev/null
+++ b/libchrome/base/json/json_reader.h
@@ -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.
+//
+// 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 <memory>
+#include <string>
+
+#include "base/base_export.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.
+  // If |json| is not a properly formed JSON string, returns nullptr.
+  // Wrap this in base::FooValue::From() to check the Value is of type Foo and
+  // convert to a FooValue at the same time.
+  static std::unique_ptr<Value> Read(StringPiece json);
+
+  // Same as Read() above, but the parser respects the given |options|.
+  static std::unique_ptr<Value> Read(StringPiece json, int options);
+
+  // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
+  // are optional. If specified and nullptr 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 std::unique_ptr<Value> ReadAndReturnError(
+      const StringPiece& json,
+      int options,  // JSONParserOptions
+      int* error_code_out,
+      std::string* error_msg_out,
+      int* error_line_out = nullptr,
+      int* error_column_out = nullptr);
+
+  // 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);
+
+  // Non-static version of Read() above.
+  std::unique_ptr<Value> ReadToValue(StringPiece 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:
+  std::unique_ptr<internal::JSONParser> parser_;
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_READER_H_
diff --git a/libchrome/base/json/json_reader_unittest.cc b/libchrome/base/json/json_reader_unittest.cc
new file mode 100644
index 0000000..84732c4
--- /dev/null
+++ b/libchrome/base/json/json_reader_unittest.cc
@@ -0,0 +1,683 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <memory>
+
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+#include "base/base_paths.h"
+#include "base/path_service.h"
+#endif
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.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
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("   null   ");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+  }
+
+  {
+    // Invalid JSON string
+    EXPECT_FALSE(JSONReader().ReadToValue("nu"));
+  }
+
+  {
+    // Simple bool
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("true  ");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+  }
+
+  {
+    // Embedded comment
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("/* comment */null");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+    root = JSONReader().ReadToValue("40 /* comment */");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+    root = JSONReader().ReadToValue("true // comment");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+    root = JSONReader().ReadToValue("/* comment */\"sample string\"");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+    std::string value;
+    EXPECT_TRUE(root->GetAsString(&value));
+    EXPECT_EQ("sample string", value);
+    std::unique_ptr<ListValue> list = ListValue::From(
+        JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]"));
+    ASSERT_TRUE(list);
+    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);
+    list = ListValue::From(JSONReader().ReadToValue("[1, /*a*/2, 3]"));
+    ASSERT_TRUE(list);
+    EXPECT_EQ(3u, list->GetSize());
+    root = JSONReader().ReadToValue("/* comment **/42");
+    ASSERT_TRUE(root);
+    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);
+    EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+    EXPECT_TRUE(root->GetAsInteger(&int_val));
+    EXPECT_EQ(44, int_val);
+  }
+
+  {
+    // Test number formats
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("43");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+    int int_val = 0;
+    EXPECT_TRUE(root->GetAsInteger(&int_val));
+    EXPECT_EQ(43, int_val);
+  }
+
+  {
+    // According to RFC4627, oct, hex, and leading zeros are invalid JSON.
+    EXPECT_FALSE(JSONReader().ReadToValue("043"));
+    EXPECT_FALSE(JSONReader().ReadToValue("0x43"));
+    EXPECT_FALSE(JSONReader().ReadToValue("00"));
+  }
+
+  {
+    // Test 0 (which needs to be special cased because of the leading zero
+    // clause).
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("0");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+    int 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
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("2147483648");
+    ASSERT_TRUE(root);
+    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);
+    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
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("43.1");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+    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);
+    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);
+    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);
+    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);
+    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);
+    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.
+    EXPECT_FALSE(JSONReader().ReadToValue("1."));
+    EXPECT_FALSE(JSONReader().ReadToValue(".1"));
+    EXPECT_FALSE(JSONReader().ReadToValue("1.e10"));
+  }
+
+  {
+    // Exponent must have a digit following the 'e'.
+    EXPECT_FALSE(JSONReader().ReadToValue("1e"));
+    EXPECT_FALSE(JSONReader().ReadToValue("1E"));
+    EXPECT_FALSE(JSONReader().ReadToValue("1e1."));
+    EXPECT_FALSE(JSONReader().ReadToValue("1e1.0"));
+  }
+
+  {
+    // INF/-INF/NaN are not valid
+    EXPECT_FALSE(JSONReader().ReadToValue("1e1000"));
+    EXPECT_FALSE(JSONReader().ReadToValue("-1e1000"));
+    EXPECT_FALSE(JSONReader().ReadToValue("NaN"));
+    EXPECT_FALSE(JSONReader().ReadToValue("nan"));
+    EXPECT_FALSE(JSONReader().ReadToValue("inf"));
+  }
+
+  {
+    // Invalid number formats
+    EXPECT_FALSE(JSONReader().ReadToValue("4.3.1"));
+    EXPECT_FALSE(JSONReader().ReadToValue("4e3.1"));
+  }
+
+  {
+    // Test string parser
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("\"hello world\"");
+    ASSERT_TRUE(root);
+    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
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\"");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+    std::string str_val;
+    EXPECT_TRUE(root->GetAsString(&str_val));
+    EXPECT_EQ("", str_val);
+  }
+
+  {
+    // Test basic string escapes
+    std::unique_ptr<Value> root =
+        JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+    std::string str_val;
+    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.
+    std::unique_ptr<Value> root =
+        JSONReader().ReadToValue("\"\\x41\\x00\\u1234\"");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+    std::string str_val;
+    EXPECT_TRUE(root->GetAsString(&str_val));
+    EXPECT_EQ(std::wstring(L"A\0\x1234", 3), UTF8ToWide(str_val));
+  }
+
+  {
+    // Test invalid strings
+    EXPECT_FALSE(JSONReader().ReadToValue("\"no closing quote"));
+    EXPECT_FALSE(JSONReader().ReadToValue("\"\\z invalid escape char\""));
+    EXPECT_FALSE(JSONReader().ReadToValue("\"\\xAQ invalid hex code\""));
+    EXPECT_FALSE(JSONReader().ReadToValue("not enough hex chars\\x1\""));
+    EXPECT_FALSE(JSONReader().ReadToValue("\"not enough escape chars\\u123\""));
+    EXPECT_FALSE(
+        JSONReader().ReadToValue("\"extra backslash at end of input\\\""));
+  }
+
+  {
+    // Basic array
+    std::unique_ptr<ListValue> list =
+        ListValue::From(JSONReader::Read("[true, false, null]"));
+    ASSERT_TRUE(list);
+    EXPECT_EQ(3U, list->GetSize());
+
+    // Test with trailing comma.  Should be parsed the same as above.
+    std::unique_ptr<Value> root2 =
+        JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS);
+    EXPECT_TRUE(list->Equals(root2.get()));
+  }
+
+  {
+    // Empty array
+    std::unique_ptr<ListValue> list = ListValue::From(JSONReader::Read("[]"));
+    ASSERT_TRUE(list);
+    EXPECT_EQ(0U, list->GetSize());
+  }
+
+  {
+    // Nested arrays
+    std::unique_ptr<ListValue> list = ListValue::From(
+        JSONReader::Read("[[true], [], [false, [], [null]], null]"));
+    ASSERT_TRUE(list);
+    EXPECT_EQ(4U, list->GetSize());
+
+    // Lots of trailing commas.
+    std::unique_ptr<Value> root2 =
+        JSONReader::Read("[[true], [], [false, [], [null, ]  , ], null,]",
+                         JSON_ALLOW_TRAILING_COMMAS);
+    EXPECT_TRUE(list->Equals(root2.get()));
+  }
+
+  {
+    // Invalid, missing close brace.
+    EXPECT_FALSE(JSONReader::Read("[[true], [], [false, [], [null]], null"));
+
+    // Invalid, too many commas
+    EXPECT_FALSE(JSONReader::Read("[true,, null]"));
+    EXPECT_FALSE(JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS));
+
+    // Invalid, no commas
+    EXPECT_FALSE(JSONReader::Read("[true null]"));
+
+    // Invalid, trailing comma
+    EXPECT_FALSE(JSONReader::Read("[true,]"));
+  }
+
+  {
+    // Valid if we set |allow_trailing_comma| to true.
+    std::unique_ptr<ListValue> list = ListValue::From(
+        JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS));
+    ASSERT_TRUE(list);
+    EXPECT_EQ(1U, list->GetSize());
+    Value* tmp_value = nullptr;
+    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.
+    EXPECT_FALSE(JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS));
+    EXPECT_FALSE(JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS));
+    EXPECT_FALSE(JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS));
+    EXPECT_FALSE(JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS));
+  }
+
+  {
+    // Test objects
+    std::unique_ptr<DictionaryValue> dict_val =
+        DictionaryValue::From(JSONReader::Read("{}"));
+    ASSERT_TRUE(dict_val);
+
+    dict_val = DictionaryValue::From(JSONReader::Read(
+        "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"));
+    ASSERT_TRUE(dict_val);
+    double double_val = 0.0;
+    EXPECT_TRUE(dict_val->GetDouble("number", &double_val));
+    EXPECT_DOUBLE_EQ(9.87654321, double_val);
+    Value* null_val = nullptr;
+    ASSERT_TRUE(dict_val->Get("null", &null_val));
+    EXPECT_TRUE(null_val->IsType(Value::TYPE_NULL));
+    std::string str_val;
+    EXPECT_TRUE(dict_val->GetString("S", &str_val));
+    EXPECT_EQ("str", str_val);
+
+    std::unique_ptr<Value> root2 = JSONReader::Read(
+        "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }",
+        JSON_ALLOW_TRAILING_COMMAS);
+    ASSERT_TRUE(root2);
+    EXPECT_TRUE(dict_val->Equals(root2.get()));
+
+    // Test newline equivalence.
+    root2 = JSONReader::Read(
+        "{\n"
+        "  \"number\":9.87654321,\n"
+        "  \"null\":null,\n"
+        "  \"\\x53\":\"str\",\n"
+        "}\n",
+        JSON_ALLOW_TRAILING_COMMAS);
+    ASSERT_TRUE(root2);
+    EXPECT_TRUE(dict_val->Equals(root2.get()));
+
+    root2 = JSONReader::Read(
+        "{\r\n"
+        "  \"number\":9.87654321,\r\n"
+        "  \"null\":null,\r\n"
+        "  \"\\x53\":\"str\",\r\n"
+        "}\r\n",
+        JSON_ALLOW_TRAILING_COMMAS);
+    ASSERT_TRUE(root2);
+    EXPECT_TRUE(dict_val->Equals(root2.get()));
+  }
+
+  {
+    // Test nesting
+    std::unique_ptr<DictionaryValue> dict_val =
+        DictionaryValue::From(JSONReader::Read(
+            "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}"));
+    ASSERT_TRUE(dict_val);
+    DictionaryValue* inner_dict = nullptr;
+    ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict));
+    ListValue* inner_array = nullptr;
+    ASSERT_TRUE(inner_dict->GetList("array", &inner_array));
+    EXPECT_EQ(1U, inner_array->GetSize());
+    bool bool_value = true;
+    EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value));
+    EXPECT_FALSE(bool_value);
+    inner_dict = nullptr;
+    EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict));
+
+    std::unique_ptr<Value> root2 = JSONReader::Read(
+        "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
+        JSON_ALLOW_TRAILING_COMMAS);
+    EXPECT_TRUE(dict_val->Equals(root2.get()));
+  }
+
+  {
+    // Test keys with periods
+    std::unique_ptr<DictionaryValue> dict_val = DictionaryValue::From(
+        JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}"));
+    ASSERT_TRUE(dict_val);
+    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);
+    DictionaryValue* inner_dict = nullptr;
+    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);
+
+    dict_val =
+        DictionaryValue::From(JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}"));
+    ASSERT_TRUE(dict_val);
+    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
+    EXPECT_FALSE(JSONReader::Read("{\"a\": true"));
+
+    // Invalid, keys must be quoted
+    EXPECT_FALSE(JSONReader::Read("{foo:true}"));
+
+    // Invalid, trailing comma
+    EXPECT_FALSE(JSONReader::Read("{\"a\":true,}"));
+
+    // Invalid, too many commas
+    EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}"));
+    EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}",
+                                  JSON_ALLOW_TRAILING_COMMAS));
+
+    // Invalid, no separator
+    EXPECT_FALSE(JSONReader::Read("{\"a\" \"b\"}"));
+
+    // Invalid, lone comma.
+    EXPECT_FALSE(JSONReader::Read("{,}"));
+    EXPECT_FALSE(JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS));
+    EXPECT_FALSE(
+        JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS));
+    EXPECT_FALSE(JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS));
+    EXPECT_FALSE(JSONReader::Read("{\"a\":true,,\"b\":false}",
+                                  JSON_ALLOW_TRAILING_COMMAS));
+  }
+
+  {
+    // Test stack overflow
+    std::string evil(1000000, '[');
+    evil.append(std::string(1000000, ']'));
+    EXPECT_FALSE(JSONReader::Read(evil));
+  }
+
+  {
+    // 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("[]]");
+    std::unique_ptr<ListValue> list =
+        ListValue::From(JSONReader::Read(not_evil));
+    ASSERT_TRUE(list);
+    EXPECT_EQ(5001U, list->GetSize());
+  }
+
+  {
+    // Test utf8 encoded input
+    std::unique_ptr<Value> root =
+        JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\"");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+    std::string str_val;
+    EXPECT_TRUE(root->GetAsString(&str_val));
+    EXPECT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val));
+
+    std::unique_ptr<DictionaryValue> dict_val =
+        DictionaryValue::From(JSONReader().ReadToValue(
+            "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}"));
+    ASSERT_TRUE(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
+    EXPECT_FALSE(JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\""));
+    EXPECT_FALSE(JSONReader().ReadToValue("\"123\xc0\x81\""));
+    EXPECT_FALSE(JSONReader().ReadToValue("\"abc\xc0\xae\""));
+  }
+
+  {
+    // Test utf16 encoded strings.
+    std::unique_ptr<Value> root = JSONReader().ReadToValue("\"\\u20ac3,14\"");
+    ASSERT_TRUE(root);
+    EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+    std::string str_val;
+    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);
+    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.
+    };
+    std::unique_ptr<Value> root;
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      root = JSONReader().ReadToValue(cases[i]);
+      EXPECT_FALSE(root) << cases[i];
+    }
+  }
+
+  {
+    // Test literal root objects.
+    std::unique_ptr<Value> root = JSONReader::Read("null");
+    EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+
+    root = JSONReader::Read("true");
+    ASSERT_TRUE(root);
+    bool bool_value;
+    EXPECT_TRUE(root->GetAsBoolean(&bool_value));
+    EXPECT_TRUE(bool_value);
+
+    root = JSONReader::Read("10");
+    ASSERT_TRUE(root);
+    int integer_value;
+    EXPECT_TRUE(root->GetAsInteger(&integer_value));
+    EXPECT_EQ(10, integer_value);
+
+    root = JSONReader::Read("\"root\"");
+    ASSERT_TRUE(root);
+    std::string str_val;
+    EXPECT_TRUE(root->GetAsString(&str_val));
+    EXPECT_EQ("root", str_val);
+  }
+}
+
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+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.AppendASCII("bom_feff.json"), &input));
+
+  JSONReader reader;
+  std::unique_ptr<Value> root(reader.ReadToValue(input));
+  ASSERT_TRUE(root) << reader.GetErrorMessage();
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+}
+#endif  // !__ANDROID__ && !__ANDROID_HOST__
+
+// Tests that the root of a JSON object can be deleted safely while its
+// children outlive it.
+TEST(JSONReaderTest, StringOptimizations) {
+  std::unique_ptr<Value> dict_literal_0;
+  std::unique_ptr<Value> dict_literal_1;
+  std::unique_ptr<Value> dict_string_0;
+  std::unique_ptr<Value> dict_string_1;
+  std::unique_ptr<Value> list_value_0;
+  std::unique_ptr<Value> list_value_1;
+
+  {
+    std::unique_ptr<Value> root = JSONReader::Read(
+        "{"
+        "  \"test\": {"
+        "    \"foo\": true,"
+        "    \"bar\": 3.14,"
+        "    \"baz\": \"bat\","
+        "    \"moo\": \"cow\""
+        "  },"
+        "  \"list\": ["
+        "    \"a\","
+        "    \"b\""
+        "  ]"
+        "}",
+        JSON_DETACHABLE_CHILDREN);
+    ASSERT_TRUE(root);
+
+    DictionaryValue* root_dict = nullptr;
+    ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+    DictionaryValue* dict = nullptr;
+    ListValue* list = nullptr;
+
+    ASSERT_TRUE(root_dict->GetDictionary("test", &dict));
+    ASSERT_TRUE(root_dict->GetList("list", &list));
+
+    ASSERT_TRUE(dict->Remove("foo", &dict_literal_0));
+    ASSERT_TRUE(dict->Remove("bar", &dict_literal_1));
+    ASSERT_TRUE(dict->Remove("baz", &dict_string_0));
+    ASSERT_TRUE(dict->Remove("moo", &dict_string_1));
+
+    ASSERT_EQ(2u, list->GetSize());
+    ASSERT_TRUE(list->Remove(0, &list_value_0));
+    ASSERT_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 kInvalidJson[] = {
+      "/* test *", "{\"foo\"", "{\"foo\":", "  [", "\"\\u123g\"", "{\n\"eh:\n}",
+  };
+
+  for (size_t i = 0; i < arraysize(kInvalidJson); ++i) {
+    JSONReader reader;
+    LOG(INFO) << "Sanity test " << i << ": <" << kInvalidJson[i] << ">";
+    EXPECT_FALSE(reader.ReadToValue(kInvalidJson[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/libchrome/base/json/json_string_value_serializer.cc b/libchrome/base/json/json_string_value_serializer.cc
new file mode 100644
index 0000000..cd786db
--- /dev/null
+++ b/libchrome/base/json/json_string_value_serializer.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/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() {}
+
+std::unique_ptr<Value> JSONStringValueDeserializer::Deserialize(
+    int* error_code,
+    std::string* error_str) {
+  return base::JSONReader::ReadAndReturnError(
+      json_string_, allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS
+                                          : base::JSON_PARSE_RFC,
+      error_code, error_str);
+}
diff --git a/libchrome/base/json/json_string_value_serializer.h b/libchrome/base/json/json_string_value_serializer.h
new file mode 100644
index 0000000..a97da23
--- /dev/null
+++ b/libchrome/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/files/file_path.h"
+#include "base/macros.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.
+  std::unique_ptr<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/libchrome/base/json/json_value_converter.cc b/libchrome/base/json/json_value_converter.cc
new file mode 100644
index 0000000..6f772f3
--- /dev/null
+++ b/libchrome/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/libchrome/base/json/json_value_converter.h b/libchrome/base/json/json_value_converter.h
new file mode 100644
index 0000000..4cca034
--- /dev/null
+++ b/libchrome/base/json/json_value_converter.h
@@ -0,0 +1,516 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.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_;
+  std::unique_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;
+
+      std::unique_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;
+
+      std::unique_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;
+
+      std::unique_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/libchrome/base/json/json_value_converter_unittest.cc b/libchrome/base/json/json_value_converter_unittest.cc
new file mode 100644
index 0000000..56ade24
--- /dev/null
+++ b/libchrome/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 <memory>
+#include <string>
+#include <vector>
+
+#include "base/json/json_reader.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";
+
+  std::unique_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";
+
+  std::unique_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";
+
+  std::unique_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";
+
+  std::unique_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";
+
+  std::unique_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";
+
+  std::unique_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/libchrome/base/json/json_value_serializer_unittest.cc b/libchrome/base/json/json_value_serializer_unittest.cc
new file mode 100644
index 0000000..0c079b7
--- /dev/null
+++ b/libchrome/base/json/json_value_serializer_unittest.cc
@@ -0,0 +1,500 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#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"
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+#include "base/path_service.h"
+#endif
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.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 {
+
+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) {
+  std::unique_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;
+  std::unique_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;
+  std::unique_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;
+  std::unique_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 = 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;
+  std::unique_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;
+  std::unique_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 = 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) {
+  std::unique_ptr<Value> root;
+  std::unique_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 = deserializer.Deserialize(NULL, NULL);
+  ASSERT_TRUE(root.get());
+  root_expected = 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);
+  std::unique_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);
+  std::unique_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);
+  std::unique_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 = 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 ]");
+
+  // It's ok to have a comment in a string.
+  std::unique_ptr<Value> root = JSONReader::Read("[\"// 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 = JSONReader::Read("/* /* inner */ outer */ [ 1 ]");
+  ASSERT_FALSE(root.get());
+
+  // Not a open comment token.
+  root = JSONReader::Read("/ * * / [1]");
+  ASSERT_FALSE(root.get());
+}
+
+#if !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+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);
+  std::unique_ptr<Value> root;
+  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);
+
+  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);
+  std::unique_ptr<Value> root;
+  root = 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);
+  std::unique_ptr<Value> root;
+  root = deserializer.Deserialize(NULL, NULL);
+  ASSERT_TRUE(root.get());
+}
+#endif  // !__ANDROID__ && !__ANDROID_HOST__
+
+}  // namespace
+
+}  // namespace base
diff --git a/libchrome/base/json/json_writer.cc b/libchrome/base/json/json_writer.cc
new file mode 100644
index 0000000..0b658ee
--- /dev/null
+++ b/libchrome/base/json/json_writer.cc
@@ -0,0 +1,210 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.h>
+
+#include <cmath>
+#include <limits>
+
+#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"
+#include "build/build_config.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 <= std::numeric_limits<int64_t>::max() &&
+          value >= std::numeric_limits<int64_t>::min() &&
+          std::floor(value) == value) {
+        json_string_->append(Int64ToString(static_cast<int64_t>(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 (const auto& value : *list) {
+        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/libchrome/base/json/json_writer.h b/libchrome/base/json/json_writer.h
new file mode 100644
index 0000000..ef43341
--- /dev/null
+++ b/libchrome/base/json/json_writer.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_JSON_JSON_WRITER_H_
+#define BASE_JSON_JSON_WRITER_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.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/libchrome/base/json/json_writer_unittest.cc b/libchrome/base/json/json_writer_unittest.cc
new file mode 100644
index 0000000..233ac5e
--- /dev/null
+++ b/libchrome/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/memory/ptr_util.h"
+#include "base/values.h"
+#include "build/build_config.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;
+  std::unique_ptr<ListValue> list(new ListValue());
+  std::unique_ptr<DictionaryValue> inner_dict(new DictionaryValue());
+  inner_dict->SetInteger("inner int", 10);
+  list->Append(std::move(inner_dict));
+  list->Append(WrapUnique(new ListValue()));
+  list->AppendBoolean(true);
+  root_dict.Set("list", std::move(list));
+
+  // 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);
+  std::unique_ptr<DictionaryValue> period_dict2(new DictionaryValue());
+  period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1);
+  period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
+  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.
+  std::unique_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(WrapUnique(new FundamentalValue(5)));
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_list.Append(WrapUnique(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", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_dict.SetInteger("b", 5);
+  binary_dict.Set("c", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_dict.SetInteger("d", 2);
+  binary_dict.Set("e", 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/libchrome/base/json/string_escape.cc b/libchrome/base/json/string_escape.cc
new file mode 100644
index 0000000..f67fa93
--- /dev/null
+++ b/libchrome/base/json/string_escape.cc
@@ -0,0 +1,167 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#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_t kReplacementCodePoint = 0xFFFD;
+
+// Used below in EscapeSpecialCodePoint().
+static_assert('<' == 0x3C, "less than sign must be 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_t 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;
+    // Escape the "Line Separator" and "Paragraph Separator" characters, since
+    // they should be treated like a new line \r or \n.
+    case 0x2028:
+      dest->append("\\u2028");
+      break;
+    case 0x2029:
+      dest->append("\\u2029");
+      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_t. Try and do so safely.
+  CHECK_LE(str.length(),
+           static_cast<size_t>(std::numeric_limits<int32_t>::max()));
+  const int32_t length = static_cast<int32_t>(str.length());
+
+  for (int32_t i = 0; i < length; ++i) {
+    uint32_t 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/libchrome/base/json/string_escape.h b/libchrome/base/json/string_escape.h
new file mode 100644
index 0000000..b66b7e5
--- /dev/null
+++ b/libchrome/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/libchrome/base/json/string_escape_unittest.cc b/libchrome/base/json/string_escape_unittest.cc
new file mode 100644
index 0000000..ae3d82a
--- /dev/null
+++ b/libchrome/base/json/string_escape_unittest.cc
@@ -0,0 +1,189 @@
+// 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 <stddef.h>
+
+#include "base/macros.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"},
+    {"Hello\xe2\x80\xa8world", "Hello\\u2028world"},
+    {"\xe2\x80\xa9purple", "\\u2029purple"},
+  };
+
+  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"},
+    {L"Hello\u2028world", "Hello\\u2028world"},
+    {L"\u2029purple", "\\u2029purple"},
+  };
+
+  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/libchrome/base/lazy_instance.cc b/libchrome/base/lazy_instance.cc
new file mode 100644
index 0000000..5468065
--- /dev/null
+++ b/libchrome/base/lazy_instance.cc
@@ -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.
+
+#include "base/lazy_instance.h"
+
+#include "base/at_exit.h"
+#include "base/atomicops.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/libchrome/base/lazy_instance.h b/libchrome/base/lazy_instance.h
new file mode 100644
index 0000000..ac970c5
--- /dev/null
+++ b/libchrome/base/lazy_instance.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2012 The Chromium 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/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.
+#ifdef __clang__
+  #define LAZY_INSTANCE_INITIALIZER {}
+#else
+  #define LAZY_INSTANCE_INITIALIZER {0, 0}
+#endif
+
+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*) {}
+};
+
+// 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/libchrome/base/lazy_instance_unittest.cc b/libchrome/base/lazy_instance_unittest.cc
new file mode 100644
index 0000000..8947b12
--- /dev/null
+++ b/libchrome/base/lazy_instance_unittest.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2012 The Chromium Authors. 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 "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/libchrome/base/location.cc b/libchrome/base/location.cc
new file mode 100644
index 0000000..1333e6e
--- /dev/null
+++ b/libchrome/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/libchrome/base/location.h b/libchrome/base/location.h
new file mode 100644
index 0000000..21e270c
--- /dev/null
+++ b/libchrome/base/location.h
@@ -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.
+
+#ifndef BASE_LOCATION_H_
+#define BASE_LOCATION_H_
+
+#include <stddef.h>
+
+#include <cassert>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/hash.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.
+      return base::HashInts(reinterpret_cast<uintptr_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/libchrome/base/logging.cc b/libchrome/base/logging.cc
new file mode 100644
index 0000000..381e9ee
--- /dev/null
+++ b/libchrome/base/logging.cc
@@ -0,0 +1,950 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <limits.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "build/build_config.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 <asl.h>
+#include <CoreFoundation/CoreFoundation.h>
+#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>
+#endif
+#include <time.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <paths.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.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/sys_string_conversions.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 "base/files/file_path.h"
+#endif
+
+#if defined(OS_ANDROID) || defined(__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_t CurrentProcessId() {
+#if defined(OS_WIN)
+  return GetCurrentProcessId();
+#elif defined(OS_POSIX)
+  return getpid();
+#endif
+}
+
+uint64_t 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_t absolute_micro = static_cast<int64_t>(ts.tv_sec) * 1000000 +
+                            static_cast<int64_t>(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
+}
+
+// We don't need locks on Windows for atomically appending to files. The OS
+// provides this functionality.
+#if !defined(OS_WIN)
+// 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)
+      log_lock = new base::internal::LockImpl();
+
+    initialized = true;
+  }
+
+ private:
+  static void LockLogging() {
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if 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_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_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_POSIX)
+pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#endif  // OS_WIN
+
+// 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)
+    // The FILE_APPEND_DATA access mask ensures that the file is atomically
+    // appended to across accesses from multiple threads.
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364399(v=vs.85).aspx
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
+    g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+                            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+    if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
+      // We are intentionally not using FilePath or FileUtil here to reduce the
+      // dependencies of the logging implementation. For e.g. FilePath and
+      // FileUtil depend on shell32 and user32.dll. This is not acceptable for
+      // some consumers of base logging like chrome_elf, etc.
+      // Please don't change the code below to use FilePath.
+      // try the current directory
+      wchar_t system_buffer[MAX_PATH];
+      system_buffer[0] = 0;
+      DWORD len = ::GetCurrentDirectory(arraysize(system_buffer),
+                                        system_buffer);
+      if (len == 0 || len > arraysize(system_buffer))
+        return false;
+
+      *g_log_file_name = system_buffer;
+      // Append a trailing backslash if needed.
+      if (g_log_file_name->back() != L'\\')
+        *g_log_file_name += L"\\";
+      *g_log_file_name += L"debug.log";
+
+      g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
+                              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;
+      }
+    }
+#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
+  if (base::CommandLine::InitializedForCurrentProcess()) {
+    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;
+
+#if !defined(OS_WIN)
+  LoggingLock::Init(settings.lock_log, settings.log_file);
+  LoggingLock logging_lock;
+#endif
+
+  // 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;
+}
+
+bool ShouldCreateLogMessage(int severity) {
+  if (severity < g_min_log_level)
+    return false;
+
+  // Return true here unless we know ~LogMessage won't do anything. Note that
+  // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even
+  // when g_logging_destination is LOG_NONE.
+  return g_logging_destination != LOG_NONE || log_message_handler ||
+         severity >= kAlwaysPrintErrorLevel;
+}
+
+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);
+
+void MakeCheckOpValueString(std::ostream* os, std::nullptr_t) {
+  (*os) << "nullptr";
+}
+
+#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)
+  MessageBoxW(nullptr, base::UTF8ToUTF16(str).c_str(), 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, const char* condition)
+    : severity_(LOG_FATAL), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << condition << ". ";
+}
+
+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(OFFICIAL_BUILD) && !defined(OS_NACL) && !defined(__UCLIBC__)
+  if (severity_ == LOG_FATAL && !base::debug::BeingDebugged()) {
+    // Include a stack trace on a fatal, unless a debugger is attached.
+    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_MACOSX)
+    // In LOG_TO_SYSTEM_DEBUG_LOG mode, log messages are always written to
+    // stderr. If stderr is /dev/null, also log via ASL (Apple System Log). If
+    // there's something weird about stderr, assume that log messages are going
+    // nowhere and log via ASL too. Messages logged via ASL show up in
+    // Console.app.
+    //
+    // Programs started by launchd, as UI applications normally are, have had
+    // stderr connected to /dev/null since OS X 10.8. Prior to that, stderr was
+    // a pipe to launchd, which logged what it received (see log_redirect_fd in
+    // 10.7.5 launchd-392.39/launchd/src/launchd_core_logic.c).
+    //
+    // Another alternative would be to determine whether stderr is a pipe to
+    // launchd and avoid logging via ASL only in that case. See 10.7.5
+    // CF-635.21/CFUtilities.c also_do_stderr(). This would result in logging to
+    // both stderr and ASL even in tests, where it's undesirable to log to the
+    // system log at all.
+    //
+    // Note that the ASL client by default discards messages whose levels are
+    // below ASL_LEVEL_NOTICE. It's possible to change that with
+    // asl_set_filter(), but this is pointless because syslogd normally applies
+    // the same filter.
+    const bool log_via_asl = []() {
+      struct stat stderr_stat;
+      if (fstat(fileno(stderr), &stderr_stat) == -1) {
+        return true;
+      }
+      if (!S_ISCHR(stderr_stat.st_mode)) {
+        return false;
+      }
+
+      struct stat dev_null_stat;
+      if (stat(_PATH_DEVNULL, &dev_null_stat) == -1) {
+        return true;
+      }
+
+      return !S_ISCHR(dev_null_stat.st_mode) ||
+             stderr_stat.st_rdev == dev_null_stat.st_rdev;
+    }();
+
+    if (log_via_asl) {
+      // Log roughly the same way that CFLog() and NSLog() would. See 10.10.5
+      // CF-1153.18/CFUtilities.c __CFLogCString().
+      //
+      // The ASL facility is set to the main bundle ID if available. Otherwise,
+      // "com.apple.console" is used.
+      CFBundleRef main_bundle = CFBundleGetMainBundle();
+      CFStringRef main_bundle_id_cf =
+          main_bundle ? CFBundleGetIdentifier(main_bundle) : nullptr;
+      std::string asl_facility =
+          main_bundle_id_cf ? base::SysCFStringRefToUTF8(main_bundle_id_cf)
+                            : std::string("com.apple.console");
+
+      class ASLClient {
+       public:
+        explicit ASLClient(const std::string& asl_facility)
+            : client_(asl_open(nullptr,
+                               asl_facility.c_str(),
+                               ASL_OPT_NO_DELAY)) {}
+        ~ASLClient() { asl_close(client_); }
+
+        aslclient get() const { return client_; }
+
+       private:
+        aslclient client_;
+        DISALLOW_COPY_AND_ASSIGN(ASLClient);
+      } asl_client(asl_facility);
+
+      class ASLMessage {
+       public:
+        ASLMessage() : message_(asl_new(ASL_TYPE_MSG)) {}
+        ~ASLMessage() { asl_free(message_); }
+
+        aslmsg get() const { return message_; }
+
+       private:
+        aslmsg message_;
+        DISALLOW_COPY_AND_ASSIGN(ASLMessage);
+      } asl_message;
+
+      // By default, messages are only readable by the admin group. Explicitly
+      // make them readable by the user generating the messages.
+      char euid_string[12];
+      snprintf(euid_string, arraysize(euid_string), "%d", geteuid());
+      asl_set(asl_message.get(), ASL_KEY_READ_UID, euid_string);
+
+      // Map Chrome log severities to ASL log levels.
+      const char* const asl_level_string = [](LogSeverity severity) {
+        // ASL_LEVEL_* are ints, but ASL needs equivalent strings. This
+        // non-obvious two-step macro trick achieves what's needed.
+        // https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
+#define ASL_LEVEL_STR(level) ASL_LEVEL_STR_X(level)
+#define ASL_LEVEL_STR_X(level) #level
+        switch (severity) {
+          case LOG_INFO:
+            return ASL_LEVEL_STR(ASL_LEVEL_INFO);
+          case LOG_WARNING:
+            return ASL_LEVEL_STR(ASL_LEVEL_WARNING);
+          case LOG_ERROR:
+            return ASL_LEVEL_STR(ASL_LEVEL_ERR);
+          case LOG_FATAL:
+            return ASL_LEVEL_STR(ASL_LEVEL_CRIT);
+          default:
+            return severity < 0 ? ASL_LEVEL_STR(ASL_LEVEL_DEBUG)
+                                : ASL_LEVEL_STR(ASL_LEVEL_NOTICE);
+        }
+#undef ASL_LEVEL_STR
+#undef ASL_LEVEL_STR_X
+      }(severity_);
+      asl_set(asl_message.get(), ASL_KEY_LEVEL, asl_level_string);
+
+      asl_set(asl_message.get(), ASL_KEY_MSG, str_newline.c_str());
+
+      asl_send(asl_client.get(), asl_message.get());
+    }
+#elif defined(OS_ANDROID) || defined(__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;
+    }
+#if defined(OS_ANDROID)
+    __android_log_write(priority, "chromium", str_newline.c_str());
+#else
+    __android_log_write(
+        priority,
+        base::CommandLine::InitializedForCurrentProcess() ?
+            base::CommandLine::ForCurrentProcess()->
+                GetProgram().BaseName().value().c_str() : nullptr,
+        str_newline.c_str());
+#endif  // defined(OS_ANDROID)
+#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.
+#if !defined(OS_WIN)
+    LoggingLock::Init(LOCK_LOG_FILE, nullptr);
+    LoggingLock logging_lock;
+#endif
+    if (InitializeLogFileHandle()) {
+#if defined(OS_WIN)
+      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
+      if (!base::debug::BeingDebugged()) {
+        // Displaying a dialog is unnecessary when debugging and can complicate
+        // debugging.
+        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);
+#if defined(__ANDROID__) || defined(ANDROID)
+    struct tm local_time;
+    memset(&local_time, 0, sizeof(local_time));
+#else
+    struct tm local_time = {0};
+#endif
+#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() {
+#if !defined(OS_WIN)
+  LoggingLock logging_lock;
+#endif
+  CloseLogFileUnlocked();
+}
+
+void RawLog(int level, const char* message) {
+  if (level >= g_min_log_level && message) {
+    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)
+bool IsLoggingToFileEnabled() {
+  return g_logging_destination & LOG_TO_FILE;
+}
+
+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 << (wstr ? base::WideToUTF8(wstr) : std::string());
+}
diff --git a/libchrome/base/logging.h b/libchrome/base/logging.h
new file mode 100644
index 0000000..2bfc972
--- /dev/null
+++ b/libchrome/base/logging.h
@@ -0,0 +1,1010 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <cassert>
+#include <cstring>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "base/base_export.h"
+#include "base/debug/debugger.h"
+#include "base/macros.h"
+#include "base/template_util.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.
+
+// 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();
+}
+
+template<typename T>
+typename std::enable_if<std::is_enum<T>::value, std::ostream&>::type operator<<(
+    std::ostream& out, T value) {
+  return out << static_cast<typename std::underlying_type<T>::type>(value);
+}
+
+}  // namespace std
+
+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();
+
+// Used by LOG_IS_ON to lazy-evaluate stream arguments.
+BASE_EXPORT bool ShouldCreateLogMessage(int severity);
+
+// 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::ShouldCreateLogMessage(::logging::LOG_##severity))
+
+// 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))
+
+// 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 ". "
+
+#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)
+
+// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
+// boolean.
+class CheckOpResult {
+ public:
+  // |message| must be non-null if and only if the check failed.
+  CheckOpResult(std::string* message) : message_(message) {}
+  // Returns true if the check succeeded.
+  operator bool() const { return !message_; }
+  // Returns the message.
+  std::string* message() { return message_; }
+
+ private:
+  std::string* message_;
+};
+
+// 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)
+
+// Make all CHECK functions discard their log strings to reduce code
+// bloat, and improve performance, for official release builds.
+
+#if defined(COMPILER_GCC) || __clang__
+#define LOGGING_CRASH() __builtin_trap()
+#else
+#define LOGGING_CRASH() ((void)(*(volatile char*)0 = 0))
+#endif
+
+// This is not calling BreakDebugger since this is called frequently, and
+// calling an out-of-line function instead of a noreturn inline macro prevents
+// compiler optimizations.
+#define CHECK(condition)                                                \
+  !(condition) ? LOGGING_CRASH() : EAT_STREAM_PARAMETERS
+
+#define PCHECK(condition) CHECK(condition)
+
+#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
+
+#else  // !(OFFICIAL_BUILD && NDEBUG)
+
+#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_
+
+// Do as much work as possible out of line to reduce inline code size.
+#define CHECK(condition)                                                    \
+  LAZY_STREAM(logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
+              !(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.
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+//   CHECK_EQ(2, a);
+#define CHECK_OP(name, op, val1, val2)                                         \
+  switch (0) case 0: default:                                                  \
+  if (logging::CheckOpResult true_if_passed =                                  \
+      logging::Check##name##Impl((val1), (val2),                               \
+                                 #val1 " " #op " " #val2))                     \
+   ;                                                                           \
+  else                                                                         \
+    logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
+
+#endif  // !(OFFICIAL_BUILD && NDEBUG)
+
+// This formats a value for a failing CHECK_XX statement.  Ordinarily,
+// it uses the definition for operator<<, with a few special cases below.
+template <typename T>
+inline typename std::enable_if<
+    base::internal::SupportsOstreamOperator<const T&>::value,
+    void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+  (*os) << v;
+}
+
+// We need overloads for enums that don't support operator<<.
+// (i.e. scoped enums where no operator<< overload was declared).
+template <typename T>
+inline typename std::enable_if<
+    !base::internal::SupportsOstreamOperator<const T&>::value &&
+        std::is_enum<T>::value,
+    void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+  (*os) << static_cast<typename base::underlying_type<T>::type>(v);
+}
+
+// We need an explicit overload for std::nullptr_t.
+BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p);
+
+// 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 << " (";
+  MakeCheckOpValueString(&ss, v1);
+  ss << " vs. ";
+  MakeCheckOpValueString(&ss, v2);
+  ss << ")";
+  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)
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#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.
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+//   DCHECK_EQ(2, a);
+#define DCHECK_OP(name, op, val1, val2)                               \
+  switch (0) case 0: default:                                         \
+  if (logging::CheckOpResult true_if_passed =                         \
+      DCHECK_IS_ON() ?                                                \
+      logging::Check##name##Impl((val1), (val2),                      \
+                                 #val1 " " #op " " #val2) : nullptr)  \
+   ;                                                                  \
+  else                                                                \
+    logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK,    \
+                        true_if_passed.message()).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 don't compile correctly if one of the arguments is a pointer
+// and the other is NULL.  In new code, prefer nullptr instead.  To
+// work around this for C++98, 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)
+
+#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().  Implied severity = LOG_FATAL.
+  LogMessage(const char* file, int line, const char* condition);
+
+  // 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);
+};
+
+// 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 true if logging to file is enabled.
+BASE_EXPORT bool IsLoggingToFileEnabled();
+
+// Returns the default log file path.
+BASE_EXPORT std::wstring GetLogFileFullPath();
+#endif
+
+}  // namespace logging
+
+// 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() static_assert(false, "NOT_IMPLEMENTED")
+#elif NOTIMPLEMENTED_POLICY == 2
+#define NOTIMPLEMENTED() static_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/libchrome/base/logging_unittest.cc b/libchrome/base/logging_unittest.cc
new file mode 100644
index 0000000..8a20c54
--- /dev/null
+++ b/libchrome/base/logging_unittest.cc
@@ -0,0 +1,317 @@
+// 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/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.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, LoggingIsLazyBySeverity) {
+  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();
+}
+
+TEST_F(LoggingTest, LoggingIsLazyByDestination) {
+  MockLogSource mock_log_source;
+  MockLogSource mock_log_source_error;
+  EXPECT_CALL(mock_log_source, Log()).Times(0);
+
+  // Severity >= ERROR is always printed to stderr.
+  EXPECT_CALL(mock_log_source_error, Log()).Times(1).
+      WillRepeatedly(Return("log message"));
+
+  LoggingSettings settings;
+  settings.logging_dest = LOG_NONE;
+  InitLogging(settings);
+
+  LOG(INFO) << mock_log_source.Log();
+  LOG(WARNING) << mock_log_source.Log();
+  LOG(ERROR) << mock_log_source_error.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) || defined(DCHECK_ALWAYS_ON)
+  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_TRUE(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 DCHECK on std::nullptr_t
+  log_sink_call_count = 0;
+  const void* p_null = nullptr;
+  const void* p_not_null = &p_null;
+  DCHECK_EQ(p_null, nullptr);
+  DCHECK_EQ(nullptr, p_null);
+  DCHECK_NE(p_not_null, nullptr);
+  DCHECK_NE(nullptr, p_not_null);
+  EXPECT_EQ(0, log_sink_call_count);
+
+  // Test DCHECK on a scoped enum.
+  enum class Animal { DOG, CAT };
+  DCHECK_EQ(Animal::DOG, Animal::DOG);
+  EXPECT_EQ(0, log_sink_call_count);
+  DCHECK_EQ(Animal::DOG, Animal::CAT);
+  EXPECT_EQ(DCHECK_IS_ON() ? 1 : 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_F(LoggingTest, DCheckEqStatements) {
+  bool reached = false;
+  if (false)
+    DCHECK_EQ(false, true);           // Unreached.
+  else
+    DCHECK_EQ(true, reached = true);  // Reached, passed.
+  ASSERT_EQ(DCHECK_IS_ON() ? true : false, reached);
+
+  if (false)
+    DCHECK_EQ(false, true);           // Unreached.
+}
+
+TEST_F(LoggingTest, CheckEqStatements) {
+  bool reached = false;
+  if (false)
+    CHECK_EQ(false, true);           // Unreached.
+  else
+    CHECK_EQ(true, reached = true);  // Reached, passed.
+  ASSERT_TRUE(reached);
+
+  if (false)
+    CHECK_EQ(false, true);           // Unreached.
+}
+
+// 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/libchrome/base/mac/OWNERS b/libchrome/base/mac/OWNERS
new file mode 100644
index 0000000..093a9c8
--- /dev/null
+++ b/libchrome/base/mac/OWNERS
@@ -0,0 +1,6 @@
+mark@chromium.org
+thakis@chromium.org
+
+# sdk_forward_declarations.[h|mm] will likely need to be modified by Cocoa
+# developers in general.
+per-file sdk_forward_declarations.*=file://chrome/browser/ui/cocoa/OWNERS
diff --git a/libchrome/base/mac/bind_objc_block.h b/libchrome/base/mac/bind_objc_block.h
new file mode 100644
index 0000000..2434d44
--- /dev/null
+++ b/libchrome/base/mac/bind_objc_block.h
@@ -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.
+
+#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...)>(
+          base::mac::internal::ScopedBlockTraits<R (^)(Args...)>::Retain(
+              block)));
+}
+
+}  // namespace base
+
+#endif  // BASE_MAC_BIND_OBJC_BLOCK_H_
diff --git a/libchrome/base/mac/bundle_locations.h b/libchrome/base/mac/bundle_locations.h
new file mode 100644
index 0000000..276290b
--- /dev/null
+++ b/libchrome/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/libchrome/base/mac/bundle_locations.mm b/libchrome/base/mac/bundle_locations.mm
new file mode 100644
index 0000000..54021b8
--- /dev/null
+++ b/libchrome/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/libchrome/base/mac/cocoa_protocols.h b/libchrome/base/mac/cocoa_protocols.h
new file mode 100644
index 0000000..a28795c
--- /dev/null
+++ b/libchrome/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/libchrome/base/mac/foundation_util.h b/libchrome/base/mac/foundation_util.h
new file mode 100644
index 0000000..ee23a17
--- /dev/null
+++ b/libchrome/base/mac/foundation_util.h
@@ -0,0 +1,398 @@
+// Copyright (c) 2012 The Chromium Authors. All 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"
+#include "build/build_config.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);
+
+#if defined(__OBJC__)
+// Converts |range| to an NSRange, returning the new range in |range_out|.
+// Returns true if conversion was successful, false if the values of |range|
+// could not be converted to NSUIntegers.
+BASE_EXPORT bool CFRangeToNSRange(CFRange range,
+                                  NSRange* range_out) WARN_UNUSED_RESULT;
+#endif  // defined(__OBJC__)
+
+}  // 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/libchrome/base/mac/foundation_util.mm b/libchrome/base/mac/foundation_util.mm
new file mode 100644
index 0000000..4f6fa60
--- /dev/null
+++ b/libchrome/base/mac/foundation_util.mm
@@ -0,0 +1,476 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.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/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/sys_string_conversions.h"
+#include "build/build_config.h"
+
+#if !defined(OS_IOS)
+#import <AppKit/AppKit.h>
+#endif
+
+#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.empty())
+    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.back() != '/')
+    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:[NSFont class]]));
+  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:[NSFont class]]);
+  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:[NSFont class]]) {
+    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]);
+}
+
+bool CFRangeToNSRange(CFRange range, NSRange* range_out) {
+  if (base::IsValueInRangeForNumericType<decltype(range_out->location)>(
+          range.location) &&
+      base::IsValueInRangeForNumericType<decltype(range_out->length)>(
+          range.length) &&
+      base::IsValueInRangeForNumericType<decltype(range_out->location)>(
+          range.location + range.length)) {
+    *range_out = NSMakeRange(range.location, range.length);
+    return true;
+  }
+  return false;
+}
+
+}  // 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/libchrome/base/mac/mac_logging.h b/libchrome/base/mac/mac_logging.h
new file mode 100644
index 0000000..30e43ea
--- /dev/null
+++ b/libchrome/base/mac/mac_logging.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_MAC_MAC_LOGGING_H_
+#define BASE_MAC_MAC_LOGGING_H_
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.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 {
+
+// Returns a UTF8 description from an OS X Status error.
+BASE_EXPORT std::string DescriptionFromOSStatus(OSStatus err);
+
+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/libchrome/base/mac/mac_logging.mm b/libchrome/base/mac/mac_logging.mm
new file mode 100644
index 0000000..f0d3c07
--- /dev/null
+++ b/libchrome/base/mac/mac_logging.mm
@@ -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/mac/mac_logging.h"
+
+#import <Foundation/Foundation.h>
+
+#include <iomanip>
+
+#include "build/build_config.h"
+
+#if !defined(OS_IOS)
+#include <CoreServices/CoreServices.h>
+#endif
+
+namespace logging {
+
+std::string DescriptionFromOSStatus(OSStatus err) {
+  NSError* error =
+      [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil];
+  return error.description.UTF8String;
+}
+
+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(crbug.com/546375): Consider using NSError with NSOSStatusErrorDomain
+  // to try to get a description of the failure.
+  stream() << ": " << status_;
+#else
+  stream() << ": "
+           << DescriptionFromOSStatus(status_)
+           << " ("
+           << status_
+           << ")";
+#endif
+}
+
+}  // namespace logging
diff --git a/libchrome/base/mac/mac_util.h b/libchrome/base/mac/mac_util.h
new file mode 100644
index 0000000..84948f7
--- /dev/null
+++ b/libchrome/base/mac/mac_util.h
@@ -0,0 +1,206 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.h>
+#include <string>
+
+#include "base/base_export.h"
+
+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);
+
+// 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.
+
+// Mavericks is OS X 10.9, Darwin 13.
+BASE_EXPORT bool IsOSMavericks();
+
+// Yosemite is OS X 10.10, Darwin 14.
+BASE_EXPORT bool IsOSYosemite();
+BASE_EXPORT bool IsOSYosemiteOrEarlier();
+BASE_EXPORT bool IsOSYosemiteOrLater();
+
+// El Capitan is OS X 10.11, Darwin 15.
+BASE_EXPORT bool IsOSElCapitan();
+BASE_EXPORT bool IsOSElCapitanOrEarlier();
+BASE_EXPORT bool IsOSElCapitanOrLater();
+
+// Sierra is macOS 10.12, Darwin 16.
+BASE_EXPORT bool IsOSSierra();
+BASE_EXPORT bool IsOSSierraOrLater();
+
+// 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 IsOSLaterThanSierra_DontCallThis();
+
+// Inline functions that are redundant due to version ranges being mutually-
+// exclusive.
+inline bool IsOSYosemiteOrEarlier() { return !IsOSElCapitanOrLater(); }
+inline bool IsOSElCapitanOrEarlier() { return !IsOSSierraOrLater(); }
+
+// 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_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; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_11) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_11
+inline bool IsOSElCapitanOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_11) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_11
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_11
+inline bool IsOSElCapitan() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_12) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_12
+inline bool IsOSSierraOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_12) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_12
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_12
+inline bool IsOSSierra() { return false; }
+inline bool IsOSLaterThanSierra_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_t* major,
+                                      int32_t* minor);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_MAC_UTIL_H_
diff --git a/libchrome/base/mac/mach_logging.cc b/libchrome/base/mac/mach_logging.cc
new file mode 100644
index 0000000..7b939b3
--- /dev/null
+++ b/libchrome/base/mac/mach_logging.cc
@@ -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.
+
+#include "base/mac/mach_logging.h"
+
+#include <iomanip>
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "build/build_config.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/libchrome/base/mac/mach_logging.h b/libchrome/base/mac/mach_logging.h
new file mode 100644
index 0000000..59ab762
--- /dev/null
+++ b/libchrome/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/logging.h"
+#include "base/macros.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/libchrome/base/mac/mach_port_broker.h b/libchrome/base/mac/mach_port_broker.h
new file mode 100644
index 0000000..4554b6a
--- /dev/null
+++ b/libchrome/base/mac/mach_port_broker.h
@@ -0,0 +1,108 @@
+// Copyright 2016 The Chromium Authors. All 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_PORT_BROKER_H_
+#define BASE_MAC_MACH_PORT_BROKER_H_
+
+#include <mach/mach.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/mac/dispatch_source_mach.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+#include "base/process/port_provider_mac.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// On OS X, the task port of a process is required to collect metrics about the
+// process, and to insert Mach ports into the process. Running |task_for_pid()|
+// is only allowed for privileged code. However, a process has port rights to
+// all its subprocesses, so let the child processes send their Mach port to the
+// parent over IPC.
+//
+// Mach ports can only be sent over Mach IPC, not over the |socketpair()| that
+// the regular IPC system uses. Hence, the child processes opens a Mach
+// connection shortly after launching and ipc their mach data to the parent
+// process. A single |MachPortBroker| with a given name is expected to exist in
+// the parent process.
+//
+// Since this data arrives over a separate channel, it is not available
+// immediately after a child process has been started.
+class BASE_EXPORT MachPortBroker : public base::PortProvider {
+ public:
+  // For use in child processes. This will send the task port of the current
+  // process over Mach IPC to the port registered by name (via this class) in
+  // the parent process. Returns true if the message was sent successfully
+  // and false if otherwise.
+  static bool ChildSendTaskPortToParent(const std::string& name);
+
+  // Returns the Mach port name to use when sending or receiving messages.
+  // Does the Right Thing in the browser and in child processes.
+  static std::string GetMachPortName(const std::string& name, bool is_child);
+
+  MachPortBroker(const std::string& name);
+  ~MachPortBroker() override;
+
+  // Performs any initialization work.
+  bool Init();
+
+  // Adds a placeholder to the map for the given pid with MACH_PORT_NULL.
+  // Callers are expected to later update the port with FinalizePid(). Callers
+  // MUST acquire the lock given by GetLock() before calling this method (and
+  // release the lock afterwards).
+  void AddPlaceholderForPid(base::ProcessHandle pid);
+
+  // Removes |pid| from the task port map. Callers MUST acquire the lock given
+  // by GetLock() before calling this method (and release the lock afterwards).
+  void InvalidatePid(base::ProcessHandle pid);
+
+  // The lock that protects this MachPortBroker object. Callers MUST acquire
+  // and release this lock around calls to AddPlaceholderForPid(),
+  // InvalidatePid(), and FinalizePid();
+  base::Lock& GetLock() { return lock_; }
+
+  // Implement |base::PortProvider|.
+  mach_port_t TaskForPid(base::ProcessHandle process) const override;
+
+ private:
+  friend class MachPortBrokerTest;
+
+  // Message handler that is invoked on |dispatch_source_| when an
+  // incoming message needs to be received.
+  void HandleRequest();
+
+  // Updates the mapping for |pid| to include the given |mach_info|.  Does
+  // nothing if PlaceholderForPid() has not already been called for the given
+  // |pid|. Callers MUST acquire the lock given by GetLock() before calling
+  // this method (and release the lock afterwards).
+  void FinalizePid(base::ProcessHandle pid, mach_port_t task_port);
+
+  // Name used to identify a particular port broker.
+  const std::string name_;
+
+  // The Mach port on which the server listens.
+  base::mac::ScopedMachReceiveRight server_port_;
+
+  // The dispatch source and queue on which Mach messages will be received.
+  std::unique_ptr<base::DispatchSourceMach> dispatch_source_;
+
+  // Stores mach info for every process in the broker.
+  typedef std::map<base::ProcessHandle, mach_port_t> MachMap;
+  MachMap mach_map_;
+
+  // Mutex that guards |mach_map_|.
+  mutable base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachPortBroker);
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_MACH_PORT_BROKER_H_
diff --git a/libchrome/base/mac/mach_port_broker.mm b/libchrome/base/mac/mach_port_broker.mm
new file mode 100644
index 0000000..bd47017
--- /dev/null
+++ b/libchrome/base/mac/mach_port_broker.mm
@@ -0,0 +1,189 @@
+// Copyright 2016 The Chromium Authors. All 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_port_broker.h"
+
+#include <bsm/libbsm.h>
+#include <servers/bootstrap.h>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+namespace {
+
+// Mach message structure used in the child as a sending message.
+struct MachPortBroker_ChildSendMsg {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t child_task_port;
+};
+
+// Complement to the ChildSendMsg, this is used in the parent for receiving
+// a message. Contains a message trailer with audit information.
+struct MachPortBroker_ParentRecvMsg : public MachPortBroker_ChildSendMsg {
+  mach_msg_audit_trailer_t trailer;
+};
+
+}  // namespace
+
+// static
+bool MachPortBroker::ChildSendTaskPortToParent(const std::string& name) {
+  // Look up the named MachPortBroker port that's been registered with the
+  // bootstrap server.
+  mach_port_t parent_port;
+  kern_return_t kr = bootstrap_look_up(bootstrap_port,
+      const_cast<char*>(GetMachPortName(name, true).c_str()), &parent_port);
+  if (kr != KERN_SUCCESS) {
+    BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up";
+    return false;
+  }
+  base::mac::ScopedMachSendRight scoped_right(parent_port);
+
+  // Create the check in message. This will copy a send right on this process'
+  // (the child's) task port and send it to the parent.
+  MachPortBroker_ChildSendMsg msg;
+  bzero(&msg, sizeof(msg));
+  msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND) |
+                         MACH_MSGH_BITS_COMPLEX;
+  msg.header.msgh_remote_port = parent_port;
+  msg.header.msgh_size = sizeof(msg);
+  msg.body.msgh_descriptor_count = 1;
+  msg.child_task_port.name = mach_task_self();
+  msg.child_task_port.disposition = MACH_MSG_TYPE_PORT_SEND;
+  msg.child_task_port.type = MACH_MSG_PORT_DESCRIPTOR;
+
+  kr = mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, sizeof(msg),
+      0, MACH_PORT_NULL, 100 /*milliseconds*/, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "mach_msg";
+    return false;
+  }
+
+  return true;
+}
+
+// static
+std::string MachPortBroker::GetMachPortName(const std::string& name,
+                                            bool is_child) {
+  // In child processes, use the parent's pid.
+  const pid_t pid = is_child ? getppid() : getpid();
+  return base::StringPrintf(
+      "%s.%s.%d", base::mac::BaseBundleID(), name.c_str(), pid);
+}
+
+mach_port_t MachPortBroker::TaskForPid(base::ProcessHandle pid) const {
+  base::AutoLock lock(lock_);
+  MachPortBroker::MachMap::const_iterator it = mach_map_.find(pid);
+  if (it == mach_map_.end())
+    return MACH_PORT_NULL;
+  return it->second;
+}
+
+MachPortBroker::MachPortBroker(const std::string& name) : name_(name) {}
+
+MachPortBroker::~MachPortBroker() {}
+
+bool MachPortBroker::Init() {
+  DCHECK(server_port_.get() == MACH_PORT_NULL);
+
+  // Check in with launchd and publish the service name.
+  mach_port_t port;
+  kern_return_t kr = bootstrap_check_in(
+      bootstrap_port, GetMachPortName(name_, false).c_str(), &port);
+  if (kr != KERN_SUCCESS) {
+    BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in";
+    return false;
+  }
+  server_port_.reset(port);
+
+  // Start the dispatch source.
+  std::string queue_name =
+      base::StringPrintf("%s.MachPortBroker", base::mac::BaseBundleID());
+  dispatch_source_.reset(new base::DispatchSourceMach(
+      queue_name.c_str(), server_port_.get(), ^{ HandleRequest(); }));
+  dispatch_source_->Resume();
+
+  return true;
+}
+
+void MachPortBroker::AddPlaceholderForPid(base::ProcessHandle pid) {
+  lock_.AssertAcquired();
+  DCHECK_EQ(0u, mach_map_.count(pid));
+  mach_map_[pid] = MACH_PORT_NULL;
+}
+
+void MachPortBroker::InvalidatePid(base::ProcessHandle pid) {
+  lock_.AssertAcquired();
+
+  MachMap::iterator mach_it = mach_map_.find(pid);
+  if (mach_it != mach_map_.end()) {
+    kern_return_t kr = mach_port_deallocate(mach_task_self(), mach_it->second);
+    MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate";
+    mach_map_.erase(mach_it);
+  }
+}
+
+void MachPortBroker::HandleRequest() {
+  MachPortBroker_ParentRecvMsg msg;
+  bzero(&msg, sizeof(msg));
+  msg.header.msgh_size = sizeof(msg);
+  msg.header.msgh_local_port = server_port_.get();
+
+  const mach_msg_option_t options = MACH_RCV_MSG |
+      MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) |
+      MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
+
+  kern_return_t kr = mach_msg(&msg.header,
+                              options,
+                              0,
+                              sizeof(msg),
+                              server_port_.get(),
+                              MACH_MSG_TIMEOUT_NONE,
+                              MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "mach_msg";
+    return;
+  }
+
+  // Use the kernel audit information to make sure this message is from
+  // a task that this process spawned. The kernel audit token contains the
+  // unspoofable pid of the task that sent the message.
+  //
+  // TODO(rsesek): In the 10.7 SDK, there's audit_token_to_pid().
+  pid_t child_pid;
+  audit_token_to_au32(msg.trailer.msgh_audit,
+      NULL, NULL, NULL, NULL, NULL, &child_pid, NULL, NULL);
+
+  mach_port_t child_task_port = msg.child_task_port.name;
+
+  // Take the lock and update the broker information.
+  {
+    base::AutoLock lock(lock_);
+    FinalizePid(child_pid, child_task_port);
+  }
+  NotifyObservers(child_pid);
+}
+
+void MachPortBroker::FinalizePid(base::ProcessHandle pid,
+                                 mach_port_t task_port) {
+  lock_.AssertAcquired();
+
+  MachMap::iterator it = mach_map_.find(pid);
+  if (it == mach_map_.end()) {
+    // Do nothing for unknown pids.
+    LOG(ERROR) << "Unknown process " << pid << " is sending Mach IPC messages!";
+    return;
+  }
+
+  DCHECK(it->second == MACH_PORT_NULL);
+  if (it->second == MACH_PORT_NULL)
+    it->second = task_port;
+}
+
+}  // namespace base
diff --git a/libchrome/base/mac/mach_port_broker_unittest.cc b/libchrome/base/mac/mach_port_broker_unittest.cc
new file mode 100644
index 0000000..bff8eb6
--- /dev/null
+++ b/libchrome/base/mac/mach_port_broker_unittest.cc
@@ -0,0 +1,133 @@
+// Copyright 2016 The Chromium Authors. All 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_port_broker.h"
+
+#include "base/command_line.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+namespace {
+const char kBootstrapPortName[] = "thisisatest";
+}
+
+class MachPortBrokerTest : public testing::Test,
+                           public base::PortProvider::Observer {
+ public:
+  MachPortBrokerTest()
+      : broker_(kBootstrapPortName),
+        event_(base::WaitableEvent::ResetPolicy::MANUAL,
+               base::WaitableEvent::InitialState::NOT_SIGNALED),
+        received_process_(kNullProcessHandle) {
+    broker_.AddObserver(this);
+  }
+  ~MachPortBrokerTest() override {
+    broker_.RemoveObserver(this);
+  }
+
+  // Helper function to acquire/release locks and call |PlaceholderForPid()|.
+  void AddPlaceholderForPid(base::ProcessHandle pid) {
+    base::AutoLock lock(broker_.GetLock());
+    broker_.AddPlaceholderForPid(pid);
+  }
+
+  // Helper function to acquire/release locks and call |FinalizePid()|.
+  void FinalizePid(base::ProcessHandle pid,
+                   mach_port_t task_port) {
+    base::AutoLock lock(broker_.GetLock());
+    broker_.FinalizePid(pid, task_port);
+  }
+
+  void WaitForTaskPort() {
+    event_.Wait();
+  }
+
+  // base::PortProvider::Observer:
+  void OnReceivedTaskPort(ProcessHandle process) override {
+    received_process_ = process;
+    event_.Signal();
+  }
+
+ protected:
+  MachPortBroker broker_;
+  WaitableEvent event_;
+  ProcessHandle received_process_;
+};
+
+TEST_F(MachPortBrokerTest, Locks) {
+  // Acquire and release the locks.  Nothing bad should happen.
+  base::AutoLock lock(broker_.GetLock());
+}
+
+TEST_F(MachPortBrokerTest, AddPlaceholderAndFinalize) {
+  // Add a placeholder for PID 1.
+  AddPlaceholderForPid(1);
+  EXPECT_EQ(0u, broker_.TaskForPid(1));
+
+  // Finalize PID 1.
+  FinalizePid(1, 100u);
+  EXPECT_EQ(100u, broker_.TaskForPid(1));
+
+  // Should be no entry for PID 2.
+  EXPECT_EQ(0u, broker_.TaskForPid(2));
+}
+
+TEST_F(MachPortBrokerTest, FinalizeUnknownPid) {
+  // Finalizing an entry for an unknown pid should not add it to the map.
+  FinalizePid(1u, 100u);
+  EXPECT_EQ(0u, broker_.TaskForPid(1u));
+}
+
+MULTIPROCESS_TEST_MAIN(MachPortBrokerTestChild) {
+  CHECK(base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapPortName));
+  return 0;
+}
+
+TEST_F(MachPortBrokerTest, ReceivePortFromChild) {
+  ASSERT_TRUE(broker_.Init());
+  CommandLine command_line(
+      base::GetMultiProcessTestChildBaseCommandLine());
+  broker_.GetLock().Acquire();
+  base::Process test_child_process = base::SpawnMultiProcessTestChild(
+      "MachPortBrokerTestChild", command_line, LaunchOptions());
+  broker_.AddPlaceholderForPid(test_child_process.Handle());
+  broker_.GetLock().Release();
+
+  WaitForTaskPort();
+  EXPECT_EQ(test_child_process.Handle(), received_process_);
+
+  int rv = -1;
+  ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
+      TestTimeouts::action_timeout(), &rv));
+  EXPECT_EQ(0, rv);
+
+  EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
+            broker_.TaskForPid(test_child_process.Handle()));
+}
+
+TEST_F(MachPortBrokerTest, ReceivePortFromChildWithoutAdding) {
+  ASSERT_TRUE(broker_.Init());
+  CommandLine command_line(
+      base::GetMultiProcessTestChildBaseCommandLine());
+  broker_.GetLock().Acquire();
+  base::Process test_child_process = base::SpawnMultiProcessTestChild(
+      "MachPortBrokerTestChild", command_line, LaunchOptions());
+  broker_.GetLock().Release();
+
+  int rv = -1;
+  ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
+      TestTimeouts::action_timeout(), &rv));
+  EXPECT_EQ(0, rv);
+
+  EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
+            broker_.TaskForPid(test_child_process.Handle()));
+}
+
+}  // namespace base
diff --git a/libchrome/base/mac/mach_port_util.cc b/libchrome/base/mac/mach_port_util.cc
new file mode 100644
index 0000000..0eee210
--- /dev/null
+++ b/libchrome/base/mac/mach_port_util.cc
@@ -0,0 +1,136 @@
+// Copyright 2016 The Chromium Authors. All 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_port_util.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace {
+
+// Struct for sending a complex Mach message.
+struct MachSendComplexMessage {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t data;
+};
+
+// Struct for receiving a complex message.
+struct MachReceiveComplexMessage {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t data;
+  mach_msg_trailer_t trailer;
+};
+
+}  // namespace
+
+kern_return_t SendMachPort(mach_port_t endpoint,
+                           mach_port_t port_to_send,
+                           int disposition) {
+  MachSendComplexMessage send_msg;
+  send_msg.header.msgh_bits =
+      MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0) | MACH_MSGH_BITS_COMPLEX;
+  send_msg.header.msgh_size = sizeof(send_msg);
+  send_msg.header.msgh_remote_port = endpoint;
+  send_msg.header.msgh_local_port = MACH_PORT_NULL;
+  send_msg.header.msgh_reserved = 0;
+  send_msg.header.msgh_id = 0;
+  send_msg.body.msgh_descriptor_count = 1;
+  send_msg.data.name = port_to_send;
+  send_msg.data.disposition = disposition;
+  send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR;
+
+  kern_return_t kr =
+      mach_msg(&send_msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
+               send_msg.header.msgh_size,
+               0,                // receive limit
+               MACH_PORT_NULL,   // receive name
+               0,                // timeout
+               MACH_PORT_NULL);  // notification port
+
+  if (kr != KERN_SUCCESS)
+    mach_port_deallocate(mach_task_self(), endpoint);
+
+  return kr;
+}
+
+base::mac::ScopedMachSendRight ReceiveMachPort(mach_port_t port_to_listen_on) {
+  MachReceiveComplexMessage recv_msg;
+  mach_msg_header_t* recv_hdr = &recv_msg.header;
+  recv_hdr->msgh_local_port = port_to_listen_on;
+  recv_hdr->msgh_size = sizeof(recv_msg);
+
+  kern_return_t kr =
+      mach_msg(recv_hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
+               recv_hdr->msgh_size, port_to_listen_on, 0, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS)
+    return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+  if (recv_msg.header.msgh_id != 0)
+    return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+  return base::mac::ScopedMachSendRight(recv_msg.data.name);
+}
+
+mach_port_name_t CreateIntermediateMachPort(
+    mach_port_t task_port,
+    base::mac::ScopedMachSendRight port_to_insert,
+    MachCreateError* error_code) {
+  DCHECK_NE(mach_task_self(), task_port);
+  DCHECK_NE(static_cast<mach_port_name_t>(MACH_PORT_NULL), task_port);
+
+  // Make a port with receive rights in the destination task.
+  mach_port_name_t endpoint;
+  kern_return_t kr =
+      mach_port_allocate(task_port, MACH_PORT_RIGHT_RECEIVE, &endpoint);
+  if (kr != KERN_SUCCESS) {
+    if (error_code)
+      *error_code = MachCreateError::ERROR_MAKE_RECEIVE_PORT;
+    return MACH_PORT_NULL;
+  }
+
+  // Change its message queue limit so that it accepts one message.
+  mach_port_limits limits = {};
+  limits.mpl_qlimit = 1;
+  kr = mach_port_set_attributes(task_port, endpoint, MACH_PORT_LIMITS_INFO,
+                                reinterpret_cast<mach_port_info_t>(&limits),
+                                MACH_PORT_LIMITS_INFO_COUNT);
+  if (kr != KERN_SUCCESS) {
+    if (error_code)
+      *error_code = MachCreateError::ERROR_SET_ATTRIBUTES;
+    mach_port_deallocate(task_port, endpoint);
+    return MACH_PORT_NULL;
+  }
+
+  // Get a send right.
+  mach_port_t send_once_right;
+  mach_msg_type_name_t send_right_type;
+  kr =
+      mach_port_extract_right(task_port, endpoint, MACH_MSG_TYPE_MAKE_SEND_ONCE,
+                              &send_once_right, &send_right_type);
+  if (kr != KERN_SUCCESS) {
+    if (error_code)
+      *error_code = MachCreateError::ERROR_EXTRACT_DEST_RIGHT;
+    mach_port_deallocate(task_port, endpoint);
+    return MACH_PORT_NULL;
+  }
+  DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND_ONCE),
+            send_right_type);
+
+  // This call takes ownership of |send_once_right|.
+  kr = base::SendMachPort(
+      send_once_right, port_to_insert.get(), MACH_MSG_TYPE_COPY_SEND);
+  if (kr != KERN_SUCCESS) {
+    if (error_code)
+      *error_code = MachCreateError::ERROR_SEND_MACH_PORT;
+    mach_port_deallocate(task_port, endpoint);
+    return MACH_PORT_NULL;
+  }
+
+  // Endpoint is intentionally leaked into the destination task. An IPC must be
+  // sent to the destination task so that it can clean up this port.
+  return endpoint;
+}
+
+}  // namespace base
diff --git a/libchrome/base/mac/mach_port_util.h b/libchrome/base/mac/mach_port_util.h
new file mode 100644
index 0000000..f7a7f32
--- /dev/null
+++ b/libchrome/base/mac/mach_port_util.h
@@ -0,0 +1,48 @@
+// Copyright 2016 The Chromium Authors. All 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_PORT_UTIL_H_
+#define BASE_MAC_MACH_PORT_UTIL_H_
+
+#include <mach/mach.h>
+
+#include "base/base_export.h"
+#include "base/mac/scoped_mach_port.h"
+
+namespace base {
+
+enum class MachCreateError {
+    ERROR_MAKE_RECEIVE_PORT,
+    ERROR_SET_ATTRIBUTES,
+    ERROR_EXTRACT_DEST_RIGHT,
+    ERROR_SEND_MACH_PORT,
+};
+
+// Sends a Mach port to |dest_port|. Assumes that |dest_port| is a send once
+// right. Takes ownership of |dest_port|.
+BASE_EXPORT kern_return_t SendMachPort(mach_port_t dest_port,
+                                       mach_port_t port_to_send,
+                                       int disposition);
+
+// Receives a Mach port from |port_to_listen_on|, which should have exactly one
+// queued message. Returns |MACH_PORT_NULL| on any error.
+BASE_EXPORT base::mac::ScopedMachSendRight ReceiveMachPort(
+    mach_port_t port_to_listen_on);
+
+// Creates an intermediate Mach port in |task_port| and sends |port_to_insert|
+// as a mach_msg to the intermediate Mach port.
+// |task_port| is the task port of another process.
+// |port_to_insert| must be a send right in the current task's name space.
+// Returns the intermediate port on success, and MACH_PORT_NULL on failure.
+// On failure, |error_code| is set if not null.
+// This method takes ownership of |port_to_insert|. On success, ownership is
+// passed to the intermediate Mach port.
+BASE_EXPORT mach_port_name_t CreateIntermediateMachPort(
+    mach_port_t task_port,
+    base::mac::ScopedMachSendRight port_to_insert,
+    MachCreateError* error_code);
+
+}  // namespace base
+
+#endif  // BASE_MAC_MACH_PORT_UTIL_H_
diff --git a/libchrome/base/mac/scoped_aedesc.h b/libchrome/base/mac/scoped_aedesc.h
new file mode 100644
index 0000000..7327092
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/mac/scoped_authorizationref.h b/libchrome/base/mac/scoped_authorizationref.h
new file mode 100644
index 0000000..03cde86
--- /dev/null
+++ b/libchrome/base/mac/scoped_authorizationref.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_SCOPED_AUTHORIZATIONREF_H_
+#define BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
+
+#include <Security/Authorization.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.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 std::unique_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/libchrome/base/mac/scoped_block.h b/libchrome/base/mac/scoped_block.h
new file mode 100644
index 0000000..8199677
--- /dev/null
+++ b/libchrome/base/mac/scoped_block.h
@@ -0,0 +1,48 @@
+// 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/mac/scoped_typeref.h"
+
+#if defined(__has_feature) && __has_feature(objc_arc)
+#define BASE_MAC_BRIDGE_CAST(TYPE, VALUE) (__bridge TYPE)(VALUE)
+#else
+#define BASE_MAC_BRIDGE_CAST(TYPE, VALUE) VALUE
+#endif
+
+namespace base {
+namespace mac {
+
+namespace internal {
+
+template <typename B>
+struct ScopedBlockTraits {
+  static B InvalidValue() { return nullptr; }
+  static B Retain(B block) {
+    return BASE_MAC_BRIDGE_CAST(
+        B, Block_copy(BASE_MAC_BRIDGE_CAST(const void*, block)));
+  }
+  static void Release(B block) {
+    Block_release(BASE_MAC_BRIDGE_CAST(const void*, block));
+  }
+};
+
+}  // namespace internal
+
+// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
+// Block_release() instead of CFRetain() and CFRelease().
+
+template <typename B>
+using ScopedBlock = ScopedTypeRef<B, internal::ScopedBlockTraits<B>>;
+
+}  // namespace mac
+}  // namespace base
+
+#undef BASE_MAC_BRIDGE_CAST
+
+#endif  // BASE_MAC_SCOPED_BLOCK_H_
diff --git a/libchrome/base/mac/scoped_cffiledescriptorref.h b/libchrome/base/mac/scoped_cffiledescriptorref.h
new file mode 100644
index 0000000..923a159
--- /dev/null
+++ b/libchrome/base/mac/scoped_cffiledescriptorref.h
@@ -0,0 +1,39 @@
+// 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/scoped_generic.h"
+
+namespace base {
+namespace mac {
+
+namespace internal {
+
+struct ScopedCFFileDescriptorRefTraits {
+  static CFFileDescriptorRef InvalidValue() { return nullptr; }
+  static void Free(CFFileDescriptorRef ref) {
+    CFFileDescriptorInvalidate(ref);
+    CFRelease(ref);
+  }
+};
+
+}  // namespace internal
+
+// 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.
+using ScopedCFFileDescriptorRef =
+    ScopedGeneric<CFFileDescriptorRef,
+                  internal::ScopedCFFileDescriptorRefTraits>;
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
diff --git a/libchrome/base/mac/scoped_cftyperef.h b/libchrome/base/mac/scoped_cftyperef.h
new file mode 100644
index 0000000..ccbc5cf
--- /dev/null
+++ b/libchrome/base/mac/scoped_cftyperef.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_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 std::unique_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
+// std::unique_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 {
+
+template<typename CFT>
+struct ScopedCFTypeRefTraits {
+  static CFT InvalidValue() { return nullptr; }
+  static CFT Retain(CFT object) {
+    CFRetain(object);
+    return object;
+  }
+  static void Release(CFT object) {
+    CFRelease(object);
+  }
+};
+
+}  // namespace internal
+
+template<typename CFT>
+using ScopedCFTypeRef =
+    ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits<CFT>>;
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFTYPEREF_H_
diff --git a/libchrome/base/mac/scoped_dispatch_object.h b/libchrome/base/mac/scoped_dispatch_object.h
new file mode 100644
index 0000000..5f5d517
--- /dev/null
+++ b/libchrome/base/mac/scoped_dispatch_object.h
@@ -0,0 +1,36 @@
+// Copyright 2016 The Chromium Authors. All 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_DISPATCH_OBJECT_H_
+#define BASE_MAC_SCOPED_DISPATCH_OBJECT_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/mac/scoped_typeref.h"
+
+namespace base {
+
+namespace internal {
+
+template <typename T>
+struct ScopedDispatchObjectTraits {
+  static T InvalidValue() { return nullptr; }
+  static T Retain(T object) {
+    dispatch_retain(object);
+    return object;
+  }
+  static void Release(T object) {
+    dispatch_release(object);
+  }
+};
+
+}  // namepsace internal
+
+template <typename T>
+using ScopedDispatchObject =
+    ScopedTypeRef<T, internal::ScopedDispatchObjectTraits<T>>;
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_DISPATCH_OBJECT_H_
diff --git a/libchrome/base/mac/scoped_ioobject.h b/libchrome/base/mac/scoped_ioobject.h
new file mode 100644
index 0000000..c948cb5
--- /dev/null
+++ b/libchrome/base/mac/scoped_ioobject.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_MAC_SCOPED_IOOBJECT_H_
+#define BASE_MAC_SCOPED_IOOBJECT_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/mac/scoped_typeref.h"
+
+namespace base {
+namespace mac {
+
+namespace internal {
+
+template <typename IOT>
+struct ScopedIOObjectTraits {
+  static IOT InvalidValue() { return IO_OBJECT_NULL; }
+  static IOT Retain(IOT iot) {
+    IOObjectRetain(iot);
+    return iot;
+  }
+  static void Release(IOT iot) { IOObjectRelease(iot); }
+};
+
+}  // namespce internal
+
+// Just like ScopedCFTypeRef but for io_object_t and subclasses.
+template <typename IOT>
+using ScopedIOObject = ScopedTypeRef<IOT, internal::ScopedIOObjectTraits<IOT>>;
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_IOOBJECT_H_
diff --git a/libchrome/base/mac/scoped_ioplugininterface.h b/libchrome/base/mac/scoped_ioplugininterface.h
new file mode 100644
index 0000000..872da8e
--- /dev/null
+++ b/libchrome/base/mac/scoped_ioplugininterface.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_MAC_SCOPED_IOPLUGININTERFACE_H_
+#define BASE_MAC_SCOPED_IOPLUGININTERFACE_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/mac/scoped_typeref.h"
+
+namespace base {
+namespace mac {
+
+namespace internal {
+
+template <typename T>
+struct ScopedIOPluginInterfaceTraits {
+  static T InvalidValue() { return nullptr; }
+  static T Retain(T t) {
+    (*t)->AddRef(t);
+    return t;
+  }
+  static void Release(T t) { (*t)->Release(t); }
+};
+
+}  // namespace internal
+
+// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends
+// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular).
+template <typename T>
+using ScopedIOPluginInterface =
+    ScopedTypeRef<T**, internal::ScopedIOPluginInterfaceTraits<T**>>;
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_IOPLUGININTERFACE_H_
diff --git a/libchrome/base/mac/scoped_launch_data.h b/libchrome/base/mac/scoped_launch_data.h
new file mode 100644
index 0000000..f4db330
--- /dev/null
+++ b/libchrome/base/mac/scoped_launch_data.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_SCOPED_LAUNCH_DATA_H_
+#define BASE_MAC_SCOPED_LAUNCH_DATA_H_
+
+#include <launch.h>
+
+#include "base/scoped_generic.h"
+
+namespace base {
+namespace mac {
+
+namespace internal {
+
+struct ScopedLaunchDataTraits {
+  static launch_data_t InvalidValue() { return nullptr; }
+  static void Free(launch_data_t ldt) { launch_data_free(ldt); }
+};
+
+}  // namespace internal
+
+// Just like std::unique_ptr<> but for launch_data_t.
+using ScopedLaunchData =
+    ScopedGeneric<launch_data_t, internal::ScopedLaunchDataTraits>;
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_LAUNCH_DATA_H_
diff --git a/libchrome/base/mac/scoped_mach_port.cc b/libchrome/base/mac/scoped_mach_port.cc
new file mode 100644
index 0000000..13307f2
--- /dev/null
+++ b/libchrome/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/libchrome/base/mac/scoped_mach_port.h b/libchrome/base/mac/scoped_mach_port.h
new file mode 100644
index 0000000..67fed6b
--- /dev/null
+++ b/libchrome/base/mac/scoped_mach_port.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_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.
+using ScopedMachSendRight =
+    ScopedGeneric<mach_port_t, internal::SendRightTraits>;
+
+// 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.
+using ScopedMachReceiveRight =
+    ScopedGeneric<mach_port_t, internal::ReceiveRightTraits>;
+
+// 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.
+using ScopedMachPortSet = ScopedGeneric<mach_port_t, internal::PortSetTraits>;
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_MACH_PORT_H_
diff --git a/libchrome/base/mac/scoped_mach_vm.cc b/libchrome/base/mac/scoped_mach_vm.cc
new file mode 100644
index 0000000..d52c77f
--- /dev/null
+++ b/libchrome/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/libchrome/base/mac/scoped_mach_vm.h b/libchrome/base/mac/scoped_mach_vm.h
new file mode 100644
index 0000000..58a13f6
--- /dev/null
+++ b/libchrome/base/mac/scoped_mach_vm.h
@@ -0,0 +1,93 @@
+// 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 <stddef.h>
+
+#include <algorithm>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.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/libchrome/base/mac/scoped_nsautorelease_pool.h b/libchrome/base/mac/scoped_nsautorelease_pool.h
new file mode 100644
index 0000000..4d15e6d
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/mac/scoped_nsautorelease_pool.mm b/libchrome/base/mac/scoped_nsautorelease_pool.mm
new file mode 100644
index 0000000..e542ca8
--- /dev/null
+++ b/libchrome/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/libchrome/base/mac/scoped_nsobject.h b/libchrome/base/mac/scoped_nsobject.h
new file mode 100644
index 0000000..cc54aa0
--- /dev/null
+++ b/libchrome/base/mac/scoped_nsobject.h
@@ -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.
+
+#ifndef BASE_MAC_SCOPED_NSOBJECT_H_
+#define BASE_MAC_SCOPED_NSOBJECT_H_
+
+#include <type_traits>
+
+// 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/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/mac/scoped_typeref.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+@class NSAutoreleasePool;
+#endif
+
+namespace base {
+
+// scoped_nsobject<> is patterned after std::unique_ptr<>, but maintains
+// ownership of an NSObject subclass object.  Style deviations here are solely
+// for compatibility with std::unique_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).
+//
+// If Automatic Reference Counting (aka ARC) is enabled then the ownership
+// policy is not controllable by the user as ARC make it really difficult to
+// transfer ownership (the reference passed to scoped_nsobject constructor is
+// sunk by ARC and __attribute((ns_consumed)) appears to not work correctly
+// with Objective-C++ see https://llvm.org/bugs/show_bug.cgi?id=27887). Due to
+// that, the policy is always to |RETAIN| when using ARC.
+
+namespace internal {
+
+BASE_EXPORT id ScopedNSProtocolTraitsRetain(__unsafe_unretained id obj)
+    __attribute((ns_returns_not_retained));
+BASE_EXPORT id ScopedNSProtocolTraitsAutoRelease(__unsafe_unretained id obj)
+    __attribute((ns_returns_not_retained));
+BASE_EXPORT void ScopedNSProtocolTraitsRelease(__unsafe_unretained id obj);
+
+// Traits for ScopedTypeRef<>. As this class may be compiled from file with
+// Automatic Reference Counting enable or not all methods have annotation to
+// enforce the same code generation in both case (in particular, the Retain
+// method uses ns_returns_not_retained to prevent ARC to insert a -release
+// call on the returned value and thus defeating the -retain).
+template <typename NST>
+struct ScopedNSProtocolTraits {
+  static NST InvalidValue() __attribute((ns_returns_not_retained)) {
+    return nil;
+  }
+  static NST Retain(__unsafe_unretained NST nst)
+      __attribute((ns_returns_not_retained)) {
+    return ScopedNSProtocolTraitsRetain(nst);
+  }
+  static void Release(__unsafe_unretained NST nst) {
+    ScopedNSProtocolTraitsRelease(nst);
+  }
+};
+
+}  // namespace internal
+
+template <typename NST>
+class scoped_nsprotocol
+    : public ScopedTypeRef<NST, internal::ScopedNSProtocolTraits<NST>> {
+ public:
+  using Traits = internal::ScopedNSProtocolTraits<NST>;
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+  explicit scoped_nsprotocol(
+      NST object = Traits::InvalidValue(),
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : ScopedTypeRef<NST, Traits>(object, policy) {}
+#else
+  explicit scoped_nsprotocol(NST object = Traits::InvalidValue())
+      : ScopedTypeRef<NST, Traits>(object, base::scoped_policy::RETAIN) {}
+#endif
+
+  scoped_nsprotocol(const scoped_nsprotocol<NST>& that)
+      : ScopedTypeRef<NST, Traits>(that) {}
+
+  template <typename NSR>
+  explicit scoped_nsprotocol(const scoped_nsprotocol<NSR>& that_as_subclass)
+      : ScopedTypeRef<NST, Traits>(that_as_subclass) {}
+
+  scoped_nsprotocol(scoped_nsprotocol<NST>&& that)
+      : ScopedTypeRef<NST, Traits>(that) {}
+
+  scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) {
+    ScopedTypeRef<NST, Traits>::operator=(that);
+    return *this;
+  }
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+  void reset(NST object = Traits::InvalidValue(),
+             base::scoped_policy::OwnershipPolicy policy =
+                 base::scoped_policy::ASSUME) {
+    ScopedTypeRef<NST, Traits>::reset(object, policy);
+  }
+#else
+  void reset(NST object = Traits::InvalidValue()) {
+    ScopedTypeRef<NST, Traits>::reset(object, base::scoped_policy::RETAIN);
+  }
+#endif
+
+  // Shift reference to the autorelease pool to be released later.
+  NST autorelease() __attribute((ns_returns_not_retained)) {
+    return internal::ScopedNSProtocolTraitsAutoRelease(this->release());
+  }
+};
+
+// 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:
+  using Traits = typename scoped_nsprotocol<NST*>::Traits;
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+  explicit scoped_nsobject(
+      NST* object = Traits::InvalidValue(),
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : scoped_nsprotocol<NST*>(object, policy) {}
+#else
+  explicit scoped_nsobject(NST* object = Traits::InvalidValue())
+      : scoped_nsprotocol<NST*>(object) {}
+#endif
+
+  scoped_nsobject(const scoped_nsobject<NST>& that)
+      : scoped_nsprotocol<NST*>(that) {}
+
+  template <typename NSR>
+  explicit scoped_nsobject(const scoped_nsobject<NSR>& that_as_subclass)
+      : scoped_nsprotocol<NST*>(that_as_subclass) {}
+
+  scoped_nsobject(scoped_nsobject<NST>&& that)
+      : scoped_nsprotocol<NST*>(that) {}
+
+  scoped_nsobject& operator=(const scoped_nsobject<NST>& that) {
+    scoped_nsprotocol<NST*>::operator=(that);
+    return *this;
+  }
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+  void reset(NST* object = Traits::InvalidValue(),
+             base::scoped_policy::OwnershipPolicy policy =
+                 base::scoped_policy::ASSUME) {
+    scoped_nsprotocol<NST*>::reset(object, policy);
+  }
+#else
+  void reset(NST* object = Traits::InvalidValue()) {
+    scoped_nsprotocol<NST*>::reset(object);
+  }
+#endif
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+  static_assert(std::is_same<NST, NSAutoreleasePool>::value == false,
+                "Use ScopedNSAutoreleasePool instead");
+#endif
+};
+
+// Specialization to make scoped_nsobject<id> work.
+template<>
+class scoped_nsobject<id> : public scoped_nsprotocol<id> {
+ public:
+  using Traits = typename scoped_nsprotocol<id>::Traits;
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+  explicit scoped_nsobject(
+      id object = Traits::InvalidValue(),
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : scoped_nsprotocol<id>(object, policy) {}
+#else
+  explicit scoped_nsobject(id object = Traits::InvalidValue())
+      : scoped_nsprotocol<id>(object) {}
+#endif
+
+  scoped_nsobject(const scoped_nsobject<id>& that)
+      : scoped_nsprotocol<id>(that) {}
+
+  template <typename NSR>
+  explicit scoped_nsobject(const scoped_nsobject<NSR>& that_as_subclass)
+      : scoped_nsprotocol<id>(that_as_subclass) {}
+
+  scoped_nsobject(scoped_nsobject<id>&& that) : scoped_nsprotocol<id>(that) {}
+
+  scoped_nsobject& operator=(const scoped_nsobject<id>& that) {
+    scoped_nsprotocol<id>::operator=(that);
+    return *this;
+  }
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+  void reset(id object = Traits::InvalidValue(),
+             base::scoped_policy::OwnershipPolicy policy =
+                 base::scoped_policy::ASSUME) {
+    scoped_nsprotocol<id>::reset(object, policy);
+  }
+#else
+  void reset(id object = Traits::InvalidValue()) {
+    scoped_nsprotocol<id>::reset(object);
+  }
+#endif
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSOBJECT_H_
diff --git a/libchrome/base/mac/scoped_typeref.h b/libchrome/base/mac/scoped_typeref.h
new file mode 100644
index 0000000..b8d8a14
--- /dev/null
+++ b/libchrome/base/mac/scoped_typeref.h
@@ -0,0 +1,139 @@
+// 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/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_policy.h"
+
+namespace base {
+
+// ScopedTypeRef<> is patterned after std::unique_ptr<>, but maintains 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> {
+//     static CGLContextObj InvalidValue() { return nullptr; }
+//     static CGLContextObj Retain(CGLContextObj object) {
+//       CGLContextRetain(object);
+//       return object;
+//     }
+//     static 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;
+
+  explicit ScopedTypeRef(
+      __unsafe_unretained T object = Traits::InvalidValue(),
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : object_(object) {
+    if (object_ && policy == base::scoped_policy::RETAIN)
+      object_ = Traits::Retain(object_);
+  }
+
+  ScopedTypeRef(const ScopedTypeRef<T, Traits>& that)
+      : object_(that.object_) {
+    if (object_)
+      object_ = Traits::Retain(object_);
+  }
+
+  // This allows passing an object to a function that takes its superclass.
+  template <typename R, typename RTraits>
+  explicit ScopedTypeRef(const ScopedTypeRef<R, RTraits>& that_as_subclass)
+      : object_(that_as_subclass.get()) {
+    if (object_)
+      object_ = Traits::Retain(object_);
+  }
+
+  ScopedTypeRef(ScopedTypeRef<T, Traits>&& that) : object_(that.object_) {
+    that.object_ = Traits::InvalidValue();
+  }
+
+  ~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(__unsafe_unretained T object = Traits::InvalidValue(),
+             base::scoped_policy::OwnershipPolicy policy =
+                 base::scoped_policy::ASSUME) {
+    if (object && policy == base::scoped_policy::RETAIN)
+      object = Traits::Retain(object);
+    if (object_)
+      Traits::Release(object_);
+    object_ = object;
+  }
+
+  bool operator==(__unsafe_unretained T that) const { return object_ == that; }
+
+  bool operator!=(__unsafe_unretained T that) const { return object_ != that; }
+
+  operator T() const __attribute((ns_returns_not_retained)) { return object_; }
+
+  T get() const __attribute((ns_returns_not_retained)) { return object_; }
+
+  void swap(ScopedTypeRef& that) {
+    __unsafe_unretained T temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  // ScopedTypeRef<>::release() is like std::unique_ptr<>::release.  It is NOT
+  // a wrapper for Release().  To force a ScopedTypeRef<> object to call
+  // Release(), use ScopedTypeRef<>::reset().
+  T release() __attribute((ns_returns_not_retained)) WARN_UNUSED_RESULT {
+    __unsafe_unretained T temp = object_;
+    object_ = Traits::InvalidValue();
+    return temp;
+  }
+
+ private:
+  __unsafe_unretained T object_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_TYPEREF_H_
diff --git a/libchrome/base/mac/sdk_forward_declarations.h b/libchrome/base/mac/sdk_forward_declarations.h
new file mode 100644
index 0000000..818a1d0
--- /dev/null
+++ b/libchrome/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 <stdint.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
+
+// ----------------------------------------------------------------------------
+// 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
+
+#if !defined(MAC_OS_X_VERSION_10_11) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
+
+enum {
+  NSPressureBehaviorUnknown = -1,
+  NSPressureBehaviorPrimaryDefault = 0,
+  NSPressureBehaviorPrimaryClick = 1,
+  NSPressureBehaviorPrimaryGeneric = 2,
+  NSPressureBehaviorPrimaryAccelerator = 3,
+  NSPressureBehaviorPrimaryDeepClick = 5,
+  NSPressureBehaviorPrimaryDeepDrag = 6
+};
+typedef NSInteger NSPressureBehavior;
+
+@interface NSPressureConfiguration : NSObject
+- (instancetype)initWithPressureBehavior:(NSPressureBehavior)pressureBehavior;
+@end
+
+#endif // MAC_OS_X_VERSION_10_11
+
+// ----------------------------------------------------------------------------
+// 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 CBAdvertisementDataServiceUUIDsKey;
+#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 CBAdvertisementDataOverflowServiceUUIDsKey;
+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;
+BASE_EXPORT extern NSString* const NSAppearanceNameVibrantLight;
+#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;
+- (NSRect)convertRectToScreen:(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;
+- (NSDraggingSession*)beginDraggingSessionWithItems:(NSArray*)items
+                                              event:(NSEvent*)event
+                                             source:
+                                                 (id<NSDraggingSource>)source;
+@end
+
+@interface NSObject (ICCameraDeviceDelegateLionSDK)
+- (void)deviceDidBecomeReadyWithCompleteContentCatalog:(ICDevice*)device;
+- (void)didDownloadFile:(ICCameraFile*)file
+                  error:(NSError*)error
+                options:(NSDictionary*)options
+            contextInfo:(void*)contextInfo;
+@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
+
+BASE_EXPORT extern "C" void NSAccessibilityPostNotificationWithUserInfo(
+    id object,
+    NSString* notification,
+    NSDictionary* user_info);
+
+#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;
+- (void)setAppearance:(NSAppearance*)appearance;
+- (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 CBUUID (YosemiteSDK)
+- (NSString*)UUIDString;
+@end
+
+@interface NSViewController (YosemiteSDK)
+- (void)viewDidLoad;
+@end
+
+@interface NSWindow (YosemiteSDK)
+- (void)setTitlebarAppearsTransparent:(BOOL)flag;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// Once Chrome no longer supports OSX 10.10.2, everything within this
+// preprocessor block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_10_3) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10_3
+
+@interface NSEvent (YosemiteSDK)
+@property(readonly) NSInteger stage;
+@end
+
+@interface NSView (YosemiteSDK)
+- (void)setPressureConfiguration:(NSPressureConfiguration*)aConfiguration;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// 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/libchrome/base/mac/sdk_forward_declarations.mm b/libchrome/base/mac/sdk_forward_declarations.mm
new file mode 100644
index 0000000..4e1d7ec
--- /dev/null
+++ b/libchrome/base/mac/sdk_forward_declarations.mm
@@ -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.
+
+#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 CBAdvertisementDataServiceUUIDsKey = @"kCBAdvDataServiceUUIDs";
+#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 CBAdvertisementDataOverflowServiceUUIDsKey =
+    @"kCBAdvDataOverflowServiceUUIDs";
+
+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/libchrome/base/macros.h b/libchrome/base/macros.h
new file mode 100644
index 0000000..4c62300
--- /dev/null
+++ b/libchrome/base/macros.h
@@ -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.
+
+// 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.
+
+#if defined(ANDROID)
+// Prefer Android's libbase definitions to our own.
+#include <android-base/macros.h>
+#endif  // defined(ANDROID)
+
+// Put this in the declarations for a class to be uncopyable.
+#if !defined(DISALLOW_COPY)
+#define DISALLOW_COPY(TypeName) \
+  TypeName(const TypeName&) = delete
+#endif
+
+// Put this in the declarations for a class to be unassignable.
+#if !defined(DISALLOW_ASSIGN)
+#define DISALLOW_ASSIGN(TypeName) \
+  void operator=(const TypeName&) = delete
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+// We define this macro conditionally as it may be defined by another libraries.
+#if !defined(DISALLOW_COPY_AND_ASSIGN)
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&) = delete;      \
+  void operator=(const TypeName&) = delete
+#endif
+
+// 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.
+#if !defined(DISALLOW_IMPLICIT_CONSTRUCTORS)
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName() = delete;                           \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+#endif
+
+// 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.  For the technical details, refer to
+// http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+#if !defined(arraysize)
+template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+#endif
+
+// 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:
+//
+//   std::unique_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.
+#if !defined(CR_DEFINE_STATIC_LOCAL)
+#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
+  static type& name = *new type arguments
+#endif
+
+}  // base
+
+#endif  // BASE_MACROS_H_
diff --git a/libchrome/base/md5.cc b/libchrome/base/md5.cc
new file mode 100644
index 0000000..72c774d
--- /dev/null
+++ b/libchrome/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/libchrome/base/md5.h b/libchrome/base/md5.h
new file mode 100644
index 0000000..ef64178
--- /dev/null
+++ b/libchrome/base/md5.h
@@ -0,0 +1,78 @@
+// 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 <stddef.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/libchrome/base/md5_unittest.cc b/libchrome/base/md5_unittest.cc
new file mode 100644
index 0000000..b27efe9
--- /dev/null
+++ b/libchrome/base/md5_unittest.cc
@@ -0,0 +1,253 @@
+// 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/md5.h"
+
+#include <string.h>
+
+#include <memory>
+#include <string>
+
+#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;
+  std::unique_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;
+  std::unique_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/libchrome/base/memory/OWNERS b/libchrome/base/memory/OWNERS
new file mode 100644
index 0000000..bcaf778
--- /dev/null
+++ b/libchrome/base/memory/OWNERS
@@ -0,0 +1,2 @@
+per-file *chromeos*=skuhne@chromium.org
+per-file *chromeos*=oshima@chromium.org
diff --git a/libchrome/base/memory/aligned_memory.cc b/libchrome/base/memory/aligned_memory.cc
new file mode 100644
index 0000000..526a495
--- /dev/null
+++ b/libchrome/base/memory/aligned_memory.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/memory/aligned_memory.h"
+
+#include "base/logging.h"
+#include "build/build_config.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/libchrome/base/memory/aligned_memory.h b/libchrome/base/memory/aligned_memory.h
new file mode 100644
index 0000000..d829011
--- /dev/null
+++ b/libchrome/base/memory/aligned_memory.h
@@ -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.
+
+// 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 unique_ptr:
+//
+//   std::unique_ptr<float, AlignedFreeDeleter> my_array(
+//       static_cast<float*>(AlignedAlloc(size, alignment)));
+
+#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
+#define BASE_MEMORY_ALIGNED_MEMORY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.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_t 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 unique_ptr. E.g., use as
+//   std::unique_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/libchrome/base/memory/aligned_memory_unittest.cc b/libchrome/base/memory/aligned_memory_unittest.cc
new file mode 100644
index 0000000..abe0cf3
--- /dev/null
+++ b/libchrome/base/memory/aligned_memory_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.
+
+#include "base/memory/aligned_memory.h"
+
+#include <memory>
+
+#include "build/build_config.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) {
+  std::unique_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/libchrome/base/memory/free_deleter.h b/libchrome/base/memory/free_deleter.h
new file mode 100644
index 0000000..5604118
--- /dev/null
+++ b/libchrome/base/memory/free_deleter.h
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All 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_FREE_DELETER_H_
+#define BASE_MEMORY_FREE_DELETER_H_
+
+#include <stdlib.h>
+
+namespace base {
+
+// Function object which invokes 'free' on its parameter, which must be
+// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr:
+//
+// std::unique_ptr<int, base::FreeDeleter> foo_ptr(
+//     static_cast<int*>(malloc(sizeof(int))));
+struct FreeDeleter {
+  inline void operator()(void* ptr) const {
+    free(ptr);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_FREE_DELETER_H_
diff --git a/libchrome/base/memory/linked_ptr.h b/libchrome/base/memory/linked_ptr.h
new file mode 100644
index 0000000..649dc10
--- /dev/null
+++ b/libchrome/base/memory/linked_ptr.h
@@ -0,0 +1,179 @@
+// 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).
+//
+// 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_;
+};
+
+// TODO(http://crbug.com/556939): DEPRECATED: Use scoped_ptr instead (now that
+// we have support for moveable types inside STL containers).
+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/libchrome/base/memory/linked_ptr_unittest.cc b/libchrome/base/memory/linked_ptr_unittest.cc
new file mode 100644
index 0000000..f6bc410
--- /dev/null
+++ b/libchrome/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/libchrome/base/memory/manual_constructor.h b/libchrome/base/memory/manual_constructor.h
new file mode 100644
index 0000000..f401f62
--- /dev/null
+++ b/libchrome/base/memory/manual_constructor.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.
+
+// 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(Ts&&... params) {
+    new(space_.void_data()) Type(std::forward<Ts>(params)...);
+  }
+
+  inline void InitFromMove(ManualConstructor<Type>&& o) {
+    Init(std::move(*o));
+  }
+
+  inline void Destroy() {
+    get()->~Type();
+  }
+
+ private:
+  AlignedMemory<sizeof(Type), ALIGNOF(Type)> space_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
diff --git a/libchrome/base/memory/ptr_util.h b/libchrome/base/memory/ptr_util.h
new file mode 100644
index 0000000..8747ac9
--- /dev/null
+++ b/libchrome/base/memory/ptr_util.h
@@ -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.
+
+#ifndef BASE_MEMORY_PTR_UTIL_H_
+#define BASE_MEMORY_PTR_UTIL_H_
+
+#include <memory>
+#include <utility>
+
+namespace base {
+
+// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
+// Note that std::unique_ptr<T> has very different semantics from
+// std::unique_ptr<T[]>: do not use this helper for array allocations.
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+  return std::unique_ptr<T>(ptr);
+}
+
+namespace internal {
+
+template <typename T>
+struct MakeUniqueResult {
+  using Scalar = std::unique_ptr<T>;
+};
+
+template <typename T>
+struct MakeUniqueResult<T[]> {
+  using Array = std::unique_ptr<T[]>;
+};
+
+template <typename T, size_t N>
+struct MakeUniqueResult<T[N]> {
+  using Invalid = void;
+};
+
+}  // namespace internal
+
+// Helper to construct an object wrapped in a std::unique_ptr. This is an
+// implementation of C++14's std::make_unique that can be used in Chrome.
+//
+// MakeUnique<T>(args) should be preferred over WrapUnique(new T(args)): bare
+// calls to `new` should be treated with scrutiny.
+//
+// Usage:
+//   // ptr is a std::unique_ptr<std::string>
+//   auto ptr = MakeUnique<std::string>("hello world!");
+//
+//   // arr is a std::unique_ptr<int[]>
+//   auto arr = MakeUnique<int[]>(5);
+
+// Overload for non-array types. Arguments are forwarded to T's constructor.
+template <typename T, typename... Args>
+typename internal::MakeUniqueResult<T>::Scalar MakeUnique(Args&&... args) {
+  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+// Overload for array types of unknown bound, e.g. T[]. The array is allocated
+// with `new T[n]()` and value-initialized: note that this is distinct from
+// `new T[n]`, which default-initializes.
+template <typename T>
+typename internal::MakeUniqueResult<T>::Array MakeUnique(size_t size) {
+  return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
+}
+
+// Overload to reject array types of known bound, e.g. T[n].
+template <typename T, typename... Args>
+typename internal::MakeUniqueResult<T>::Invalid MakeUnique(Args&&... args) =
+    delete;
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_PTR_UTIL_H_
diff --git a/libchrome/base/memory/raw_scoped_refptr_mismatch_checker.h b/libchrome/base/memory/raw_scoped_refptr_mismatch_checker.h
new file mode 100644
index 0000000..5dbc183
--- /dev/null
+++ b/libchrome/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -0,0 +1,58 @@
+// 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 <tuple>
+#include <type_traits>
+
+#include "base/memory/ref_counted.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 {
+  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 = (std::is_pointer<T>::value &&
+             (std::is_convertible<T, subtle::RefCountedBase*>::value ||
+              std::is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
+  };
+};
+
+template <typename Params>
+struct ParamsUseScopedRefptrCorrectly {
+  enum { value = 0 };
+};
+
+template <>
+struct ParamsUseScopedRefptrCorrectly<std::tuple<>> {
+  enum { value = 1 };
+};
+
+template <typename Head, typename... Tail>
+struct ParamsUseScopedRefptrCorrectly<std::tuple<Head, Tail...>> {
+  enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
+                  ParamsUseScopedRefptrCorrectly<std::tuple<Tail...>>::value };
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/libchrome/base/memory/ref_counted.cc b/libchrome/base/memory/ref_counted.cc
new file mode 100644
index 0000000..f5924d0
--- /dev/null
+++ b/libchrome/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/libchrome/base/memory/ref_counted.h b/libchrome/base/memory/ref_counted.h
new file mode 100644
index 0000000..b026d9a
--- /dev/null
+++ b/libchrome/base/memory/ref_counted.h
@@ -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.
+
+#ifndef BASE_MEMORY_REF_COUNTED_H_
+#define BASE_MEMORY_REF_COUNTED_H_
+
+#include <stddef.h>
+
+#include <cassert>
+#include <iosfwd>
+#include <type_traits>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#ifndef NDEBUG
+#include "base/logging.h"
+#endif
+#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, 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 non-public, 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 {
+ public:
+  typedef T element_type;
+
+  scoped_refptr() : ptr_(NULL) {
+  }
+
+  scoped_refptr(T* p) : ptr_(p) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  // Copy constructor.
+  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  // Copy conversion constructor.
+  template <typename U,
+            typename = typename std::enable_if<
+                std::is_convertible<U*, T*>::value>::type>
+  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  // Move constructor. This is required in addition to the conversion
+  // constructor below in order for clang to warn about pessimizing moves.
+  scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
+
+  // Move conversion constructor.
+  template <typename U,
+            typename = typename std::enable_if<
+                std::is_convertible<U*, T*>::value>::type>
+  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>(std::move(r)).swap(*this);
+    return *this;
+  }
+
+  template <typename U>
+  scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
+    scoped_refptr<T>(std::move(r)).swap(*this);
+    return *this;
+  }
+
+  void swap(T** pp) {
+    T* p = ptr_;
+    ptr_ = *pp;
+    *pp = p;
+  }
+
+  void swap(scoped_refptr<T>& r) {
+    swap(&r.ptr_);
+  }
+
+  explicit operator bool() const { return 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:
+  // Friend required for move constructors that set r.ptr_ to null.
+  template <typename U>
+  friend class scoped_refptr;
+
+  // 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);
+}
+
+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>
+bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t) {
+  return !static_cast<bool>(lhs);
+}
+
+template <typename T>
+bool operator==(std::nullptr_t, const scoped_refptr<T>& rhs) {
+  return !static_cast<bool>(rhs);
+}
+
+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>
+bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
+  return !operator==(lhs, null);
+}
+
+template <typename T>
+bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
+  return !operator==(null, 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/libchrome/base/memory/ref_counted_delete_on_message_loop.h b/libchrome/base/memory/ref_counted_delete_on_message_loop.h
new file mode 100644
index 0000000..de194e8
--- /dev/null
+++ b/libchrome/base/memory/ref_counted_delete_on_message_loop.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_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/macros.h"
+#include "base/memory/ref_counted.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(scoped_refptr<SingleThreadTaskRunner> loop)
+//       : RefCountedDeleteOnMessageLoop<Foo>(std::move(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(
+      scoped_refptr<SingleThreadTaskRunner> task_runner)
+      : task_runner_(std::move(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/libchrome/base/memory/ref_counted_memory.cc b/libchrome/base/memory/ref_counted_memory.cc
new file mode 100644
index 0000000..26b78f3
--- /dev/null
+++ b/libchrome/base/memory/ref_counted_memory.cc
@@ -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.
+
+#include "base/memory/ref_counted_memory.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) {}
+
+scoped_refptr<RefCountedBytes> RefCountedBytes::TakeVector(
+    std::vector<unsigned char>* to_destroy) {
+  scoped_refptr<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
+scoped_refptr<RefCountedString> RefCountedString::TakeString(
+    std::string* to_destroy) {
+  scoped_refptr<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();
+}
+
+}  //  namespace base
diff --git a/libchrome/base/memory/ref_counted_memory.h b/libchrome/base/memory/ref_counted_memory.h
new file mode 100644
index 0000000..aa22c9e
--- /dev/null
+++ b/libchrome/base/memory/ref_counted_memory.h
@@ -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.
+
+#ifndef BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#define BASE_MEMORY_REF_COUNTED_MEMORY_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.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 scoped_refptr<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 scoped_refptr<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);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_REF_COUNTED_MEMORY_H_
diff --git a/libchrome/base/memory/ref_counted_memory_unittest.cc b/libchrome/base/memory/ref_counted_memory_unittest.cc
new file mode 100644
index 0000000..bd2ed01
--- /dev/null
+++ b/libchrome/base/memory/ref_counted_memory_unittest.cc
@@ -0,0 +1,81 @@
+// 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 <stdint.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_t> 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, 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/libchrome/base/memory/ref_counted_unittest.cc b/libchrome/base/memory/ref_counted_unittest.cc
new file mode 100644
index 0000000..7c4e07a
--- /dev/null
+++ b/libchrome/base/memory/ref_counted_unittest.cc
@@ -0,0 +1,507 @@
+// Copyright (c) 2012 The Chromium Authors. All 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;
+
+class Other : public base::RefCounted<Other> {
+ private:
+  friend class base::RefCounted<Other>;
+
+  ~Other() {}
+};
+
+scoped_refptr<Other> Overloaded(scoped_refptr<Other> other) {
+  return other;
+}
+
+scoped_refptr<SelfAssign> Overloaded(scoped_refptr<SelfAssign> self_assign) {
+  return self_assign;
+}
+
+
+}  // 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> ptr_to_an_instance = new SelfAssign;
+  EXPECT_TRUE(ptr_to_an_instance);
+  EXPECT_FALSE(!ptr_to_an_instance);
+
+  if (ptr_to_an_instance) {
+  } else {
+    ADD_FAILURE() << "Pointer to an instance should result in true.";
+  }
+
+  if (!ptr_to_an_instance) {  // check for operator!().
+    ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
+  }
+
+  scoped_refptr<SelfAssign> null_ptr;
+  EXPECT_FALSE(null_ptr);
+  EXPECT_TRUE(!null_ptr);
+
+  if (null_ptr) {
+    ADD_FAILURE() << "Null pointer should result in false.";
+  }
+
+  if (!null_ptr) {  // check for operator!().
+  } else {
+    ADD_FAILURE() << "Null pointer should result in !x being true.";
+  }
+}
+
+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, NullptrEquality) {
+  scoped_refptr<SelfAssign> ptr_to_an_instance(new SelfAssign);
+  scoped_refptr<SelfAssign> ptr_to_nullptr;
+
+  EXPECT_NE(nullptr, ptr_to_an_instance);
+  EXPECT_NE(ptr_to_an_instance, nullptr);
+  EXPECT_EQ(nullptr, ptr_to_nullptr);
+  EXPECT_EQ(ptr_to_nullptr, nullptr);
+}
+
+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, 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 = std::move(p1);
+      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 = std::move(p2);
+      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 = std::move(p2);
+      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 = std::move(p1);
+      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 = std::move(p2);
+      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 = std::move(p2);
+      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(std::move(p1));
+      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(std::move(p1));
+      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());
+}
+
+TEST(RefCountedUnitTest, TestOverloadResolutionCopy) {
+  scoped_refptr<Derived> derived(new Derived);
+  scoped_refptr<SelfAssign> expected(derived);
+  EXPECT_EQ(expected, Overloaded(derived));
+
+  scoped_refptr<Other> other(new Other);
+  EXPECT_EQ(other, Overloaded(other));
+}
+
+TEST(RefCountedUnitTest, TestOverloadResolutionMove) {
+  scoped_refptr<Derived> derived(new Derived);
+  scoped_refptr<SelfAssign> expected(derived);
+  EXPECT_EQ(expected, Overloaded(std::move(derived)));
+
+  scoped_refptr<Other> other(new Other);
+  scoped_refptr<Other> other2(other);
+  EXPECT_EQ(other2, Overloaded(std::move(other)));
+}
diff --git a/libchrome/base/memory/scoped_policy.h b/libchrome/base/memory/scoped_policy.h
new file mode 100644
index 0000000..5dbf204
--- /dev/null
+++ b/libchrome/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/libchrome/base/memory/scoped_vector.h b/libchrome/base/memory/scoped_vector.h
new file mode 100644
index 0000000..f3581ea
--- /dev/null
+++ b/libchrome/base/memory/scoped_vector.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_MEMORY_SCOPED_VECTOR_H_
+#define BASE_MEMORY_SCOPED_VECTOR_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+
+// ScopedVector wraps a vector deleting the elements from its
+// destructor.
+//
+// TODO(http://crbug.com/554289): DEPRECATED: Use std::vector instead (now that
+// we have support for moveable types inside containers).
+template <class T>
+class ScopedVector {
+ 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(ScopedVector&& other) { swap(other); }
+
+  ScopedVector& operator=(ScopedVector&& rhs) {
+    swap(rhs);
+    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(std::unique_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);
+  }
+
+  iterator insert(iterator position, std::unique_ptr<T> x) {
+    return v_.insert(position, x.release());
+  }
+
+  // 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_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedVector);
+};
+
+#endif  // BASE_MEMORY_SCOPED_VECTOR_H_
diff --git a/libchrome/base/memory/scoped_vector_unittest.cc b/libchrome/base/memory/scoped_vector_unittest.cc
new file mode 100644
index 0000000..ea3dcdc
--- /dev/null
+++ b/libchrome/base/memory/scoped_vector_unittest.cc
@@ -0,0 +1,338 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.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() {
+    if (observer_)
+      observer_->OnLifeCycleDestroy(this);
+  }
+
+ private:
+  friend class LifeCycleWatcher;
+
+  explicit LifeCycleObject(Observer* observer)
+      : observer_(observer) {
+    observer_->OnLifeCycleConstruct(this);
+  }
+
+  void DisconnectObserver() {
+    observer_ = nullptr;
+  }
+
+  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 {
+    // Stop watching the watched object. Without this, the object's destructor
+    // will call into OnLifeCycleDestroy when destructed, which happens after
+    // this destructor has finished running.
+    if (constructed_life_cycle_object_)
+      constructed_life_cycle_object_->DisconnectObserver();
+  }
+
+  // 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_;
+  std::unique_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(std::move(scoped_vector));
+    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 = std::move(scoped_vector);
+    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;
+}
+
+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;
+  std::unique_ptr<DeleteCounter> elem(new DeleteCounter(&delete_counter));
+  EXPECT_EQ(0, delete_counter);
+  {
+    ScopedVector<DeleteCounter> v;
+    v.push_back(std::move(elem));
+    EXPECT_EQ(0, delete_counter);
+  }
+  EXPECT_EQ(1, delete_counter);
+}
+
+}  // namespace
diff --git a/libchrome/base/memory/shared_memory.h b/libchrome/base/memory/shared_memory.h
new file mode 100644
index 0000000..e1c9fa7
--- /dev/null
+++ b/libchrome/base/memory/shared_memory.h
@@ -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.
+
+#ifndef BASE_MEMORY_SHARED_MEMORY_H_
+#define BASE_MEMORY_SHARED_MEMORY_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/shared_memory_handle.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <stdio.h>
+#include <sys/types.h>
+#include <semaphore.h>
+#include "base/file_descriptor_posix.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+namespace base {
+
+class FilePath;
+
+// Options for creating a shared memory object.
+struct BASE_EXPORT SharedMemoryCreateOptions {
+  SharedMemoryCreateOptions();
+
+#if !(defined(OS_MACOSX) && !defined(OS_IOS))
+  // 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;
+
+  // 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;
+#endif  // !(defined(OS_MACOSX) && !defined(OS_IOS))
+
+  // Size of the shared memory object to be created.
+  // When opening an existing object, this has no effect.
+  size_t size;
+
+  // 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(const SharedMemoryHandle& handle, bool read_only);
+
+  // 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) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+  // 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)
+  // Gets the size of the shared memory region referred to by |handle|.
+  // Returns false on a failure to determine the size. On success, populates the
+  // output variable |size|.
+  static bool GetSizeFromSharedMemoryHandle(const SharedMemoryHandle& handle,
+                                            size_t* size);
+#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);
+  }
+
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  // 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);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+
+  // 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);
+  }
+
+ private:
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID) && \
+    !(defined(OS_MACOSX) && !defined(OS_IOS))
+  bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
+  bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
+#endif
+  enum ShareMode {
+    SHARE_READONLY,
+    SHARE_CURRENT_MODE,
+  };
+  bool ShareToProcessCommon(ProcessHandle process,
+                            SharedMemoryHandle* new_handle,
+                            bool close_self,
+                            ShareMode);
+
+#if defined(OS_WIN)
+  // If true indicates this came from an external source so needs extra checks
+  // before being mapped.
+  bool external_section_;
+  std::wstring       name_;
+  win::ScopedHandle  mapped_file_;
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+  // The OS primitive that backs the shared memory region.
+  SharedMemoryHandle shm_;
+#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_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemory);
+};
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_H_
diff --git a/libchrome/base/memory/shared_memory_android.cc b/libchrome/base/memory/shared_memory_android.cc
new file mode 100644
index 0000000..5ac6776
--- /dev/null
+++ b/libchrome/base/memory/shared_memory_android.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/memory/shared_memory.h"
+
+#include <stddef.h>
+#include <sys/mman.h>
+
+#include "base/logging.h"
+
+#if defined(__ANDROID__)
+#include <cutils/ashmem.h>
+#else
+#include "third_party/ashmem/ashmem.h"
+#endif
+
+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&) {
+  // 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&, bool /*read_only*/) {
+  // ashmem doesn't support name mapping
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/libchrome/base/memory/shared_memory_handle.h b/libchrome/base/memory/shared_memory_handle.h
new file mode 100644
index 0000000..8eff26b
--- /dev/null
+++ b/libchrome/base/memory/shared_memory_handle.h
@@ -0,0 +1,164 @@
+// 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_SHARED_MEMORY_HANDLE_H_
+#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
+
+#include <stddef.h>
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include "base/process/process_handle.h"
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach.h>
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#elif defined(OS_POSIX)
+#include <sys/types.h>
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace base {
+
+class Pickle;
+
+// SharedMemoryHandle is a platform specific type which represents
+// the underlying OS handle to a shared memory segment.
+#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+typedef FileDescriptor SharedMemoryHandle;
+#elif defined(OS_WIN)
+class BASE_EXPORT SharedMemoryHandle {
+ public:
+  // The default constructor returns an invalid SharedMemoryHandle.
+  SharedMemoryHandle();
+  SharedMemoryHandle(HANDLE h, base::ProcessId pid);
+
+  // Standard copy constructor. The new instance shares the underlying OS
+  // primitives.
+  SharedMemoryHandle(const SharedMemoryHandle& handle);
+
+  // Standard assignment operator. The updated instance shares the underlying
+  // OS primitives.
+  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
+
+  // Comparison operators.
+  bool operator==(const SharedMemoryHandle& handle) const;
+  bool operator!=(const SharedMemoryHandle& handle) const;
+
+  // Closes the underlying OS resources.
+  void Close() const;
+
+  // Whether the underlying OS primitive is valid.
+  bool IsValid() const;
+
+  // Whether |pid_| is the same as the current process's id.
+  bool BelongsToCurrentProcess() const;
+
+  // Whether handle_ needs to be duplicated into the destination process when
+  // an instance of this class is passed over a Chrome IPC channel.
+  bool NeedsBrokering() const;
+
+  void SetOwnershipPassesToIPC(bool ownership_passes);
+  bool OwnershipPassesToIPC() const;
+
+  HANDLE GetHandle() const;
+  base::ProcessId GetPID() const;
+
+ private:
+  HANDLE handle_;
+
+  // The process in which |handle_| is valid and can be used. If |handle_| is
+  // invalid, this will be kNullProcessId.
+  base::ProcessId pid_;
+
+  // Whether passing this object as a parameter to an IPC message passes
+  // ownership of |handle_| to the IPC stack. This is meant to mimic the
+  // behavior of the |auto_close| parameter of FileDescriptor. This member only
+  // affects attachment-brokered SharedMemoryHandles.
+  // Defaults to |false|.
+  bool ownership_passes_to_ipc_;
+};
+#else
+class BASE_EXPORT SharedMemoryHandle {
+ public:
+  // The default constructor returns an invalid SharedMemoryHandle.
+  SharedMemoryHandle();
+
+  // Makes a Mach-based SharedMemoryHandle of the given size. On error,
+  // subsequent calls to IsValid() return false.
+  explicit SharedMemoryHandle(mach_vm_size_t size);
+
+  // Makes a Mach-based SharedMemoryHandle from |memory_object|, a named entry
+  // in the task with process id |pid|. The memory region has size |size|.
+  SharedMemoryHandle(mach_port_t memory_object,
+                     mach_vm_size_t size,
+                     base::ProcessId pid);
+
+  // Standard copy constructor. The new instance shares the underlying OS
+  // primitives.
+  SharedMemoryHandle(const SharedMemoryHandle& handle);
+
+  // Standard assignment operator. The updated instance shares the underlying
+  // OS primitives.
+  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
+
+  // Duplicates the underlying OS resources.
+  SharedMemoryHandle Duplicate() const;
+
+  // Comparison operators.
+  bool operator==(const SharedMemoryHandle& handle) const;
+  bool operator!=(const SharedMemoryHandle& handle) const;
+
+  // Whether the underlying OS primitive is valid. Once the SharedMemoryHandle
+  // is backed by a valid OS primitive, it becomes immutable.
+  bool IsValid() const;
+
+  // Exposed so that the SharedMemoryHandle can be transported between
+  // processes.
+  mach_port_t GetMemoryObject() const;
+
+  // Returns false on a failure to determine the size. On success, populates the
+  // output variable |size|. Returns 0 if the handle is invalid.
+  bool GetSize(size_t* size) const;
+
+  // The SharedMemoryHandle must be valid.
+  // Returns whether the SharedMemoryHandle was successfully mapped into memory.
+  // On success, |memory| is an output variable that contains the start of the
+  // mapped memory.
+  bool MapAt(off_t offset, size_t bytes, void** memory, bool read_only);
+
+  // Closes the underlying OS primitive.
+  void Close() const;
+
+  void SetOwnershipPassesToIPC(bool ownership_passes);
+  bool OwnershipPassesToIPC() const;
+
+ private:
+  // Shared code between copy constructor and operator=.
+  void CopyRelevantData(const SharedMemoryHandle& handle);
+
+  mach_port_t memory_object_ = MACH_PORT_NULL;
+
+  // The size of the shared memory region when |type_| is MACH. Only
+  // relevant if |memory_object_| is not |MACH_PORT_NULL|.
+  mach_vm_size_t size_ = 0;
+
+  // The pid of the process in which |memory_object_| is usable. Only
+  // relevant if |memory_object_| is not |MACH_PORT_NULL|.
+  base::ProcessId pid_ = 0;
+
+  // Whether passing this object as a parameter to an IPC message passes
+  // ownership of |memory_object_| to the IPC stack. This is meant to mimic
+  // the behavior of the |auto_close| parameter of FileDescriptor.
+  // Defaults to |false|.
+  bool ownership_passes_to_ipc_ = false;
+};
+#endif
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
diff --git a/libchrome/base/memory/shared_memory_handle_mac.cc b/libchrome/base/memory/shared_memory_handle_mac.cc
new file mode 100644
index 0000000..ad470be
--- /dev/null
+++ b/libchrome/base/memory/shared_memory_handle_mac.cc
@@ -0,0 +1,146 @@
+// 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/shared_memory_handle.h"
+
+#include <mach/mach_vm.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "base/mac/mac_util.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace base {
+
+SharedMemoryHandle::SharedMemoryHandle() {}
+
+SharedMemoryHandle::SharedMemoryHandle(mach_vm_size_t size) {
+  mach_port_t named_right;
+  kern_return_t kr = mach_make_memory_entry_64(
+      mach_task_self(),
+      &size,
+      0,  // Address.
+      MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE,
+      &named_right,
+      MACH_PORT_NULL);  // Parent handle.
+  if (kr != KERN_SUCCESS) {
+    memory_object_ = MACH_PORT_NULL;
+    return;
+  }
+
+  memory_object_ = named_right;
+  size_ = size;
+  pid_ = GetCurrentProcId();
+  ownership_passes_to_ipc_ = false;
+}
+
+SharedMemoryHandle::SharedMemoryHandle(mach_port_t memory_object,
+                                       mach_vm_size_t size,
+                                       base::ProcessId pid)
+    : memory_object_(memory_object),
+      size_(size),
+      pid_(pid),
+      ownership_passes_to_ipc_(false) {}
+
+SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle) {
+  CopyRelevantData(handle);
+}
+
+SharedMemoryHandle& SharedMemoryHandle::operator=(
+    const SharedMemoryHandle& handle) {
+  if (this == &handle)
+    return *this;
+
+  CopyRelevantData(handle);
+  return *this;
+}
+
+SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
+  if (!IsValid())
+    return SharedMemoryHandle(MACH_PORT_NULL, 0, 0);
+
+  // Increment the ref count.
+  kern_return_t kr = mach_port_mod_refs(mach_task_self(), memory_object_,
+                                        MACH_PORT_RIGHT_SEND, 1);
+  DCHECK_EQ(kr, KERN_SUCCESS);
+  SharedMemoryHandle handle(*this);
+  handle.SetOwnershipPassesToIPC(true);
+  return handle;
+}
+
+bool SharedMemoryHandle::operator==(const SharedMemoryHandle& handle) const {
+  if (!IsValid() && !handle.IsValid())
+    return true;
+
+  return memory_object_ == handle.memory_object_ && size_ == handle.size_ &&
+         pid_ == handle.pid_;
+}
+
+bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
+  return !(*this == handle);
+}
+
+bool SharedMemoryHandle::IsValid() const {
+  return memory_object_ != MACH_PORT_NULL;
+}
+
+mach_port_t SharedMemoryHandle::GetMemoryObject() const {
+  return memory_object_;
+}
+
+bool SharedMemoryHandle::GetSize(size_t* size) const {
+  if (!IsValid()) {
+    *size = 0;
+    return true;
+  }
+
+  *size = size_;
+  return true;
+}
+
+bool SharedMemoryHandle::MapAt(off_t offset,
+                               size_t bytes,
+                               void** memory,
+                               bool read_only) {
+  DCHECK(IsValid());
+  DCHECK_EQ(pid_, GetCurrentProcId());
+  kern_return_t kr = mach_vm_map(
+      mach_task_self(),
+      reinterpret_cast<mach_vm_address_t*>(memory),  // Output parameter
+      bytes,
+      0,  // Alignment mask
+      VM_FLAGS_ANYWHERE, memory_object_, offset,
+      FALSE,                                           // Copy
+      VM_PROT_READ | (read_only ? 0 : VM_PROT_WRITE),  // Current protection
+      VM_PROT_WRITE | VM_PROT_READ | VM_PROT_IS_MASK,  // Maximum protection
+      VM_INHERIT_NONE);
+  return kr == KERN_SUCCESS;
+}
+
+void SharedMemoryHandle::Close() const {
+  if (!IsValid())
+    return;
+
+  kern_return_t kr = mach_port_deallocate(mach_task_self(), memory_object_);
+  if (kr != KERN_SUCCESS)
+    DPLOG(ERROR) << "Error deallocating mach port: " << kr;
+}
+
+void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
+  ownership_passes_to_ipc_ = ownership_passes;
+}
+
+bool SharedMemoryHandle::OwnershipPassesToIPC() const {
+  return ownership_passes_to_ipc_;
+}
+
+void SharedMemoryHandle::CopyRelevantData(const SharedMemoryHandle& handle) {
+  memory_object_ = handle.memory_object_;
+  size_ = handle.size_;
+  pid_ = handle.pid_;
+  ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
+}
+
+}  // namespace base
diff --git a/libchrome/base/memory/shared_memory_mac.cc b/libchrome/base/memory/shared_memory_mac.cc
new file mode 100644
index 0000000..d15c632
--- /dev/null
+++ b/libchrome/base/memory/shared_memory_mac.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/memory/shared_memory.h"
+
+#include <mach/mach_vm.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_mach_vm.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.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 "build/build_config.h"
+
+namespace base {
+
+namespace {
+
+// Returns whether the operation succeeded.
+// |new_handle| is an output variable, populated on success. The caller takes
+// ownership of the underlying memory object.
+// |handle| is the handle to copy.
+// If |handle| is already mapped, |mapped_addr| is its mapped location.
+// Otherwise, |mapped_addr| should be |nullptr|.
+bool MakeMachSharedMemoryHandleReadOnly(SharedMemoryHandle* new_handle,
+                                        SharedMemoryHandle handle,
+                                        void* mapped_addr) {
+  if (!handle.IsValid())
+    return false;
+
+  size_t size;
+  CHECK(handle.GetSize(&size));
+
+  // Map if necessary.
+  void* temp_addr = mapped_addr;
+  base::mac::ScopedMachVM scoper;
+  if (!temp_addr) {
+    // Intentionally lower current prot and max prot to |VM_PROT_READ|.
+    kern_return_t kr = mach_vm_map(
+        mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&temp_addr),
+        size, 0, VM_FLAGS_ANYWHERE, handle.GetMemoryObject(), 0, FALSE,
+        VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+    if (kr != KERN_SUCCESS)
+      return false;
+    scoper.reset(reinterpret_cast<vm_address_t>(temp_addr),
+                 mach_vm_round_page(size));
+  }
+
+  // Make new memory object.
+  mach_port_t named_right;
+  kern_return_t kr = mach_make_memory_entry_64(
+      mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size),
+      reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ,
+      &named_right, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS)
+    return false;
+
+  *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId());
+  return true;
+}
+
+}  // namespace
+
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+    : size(0),
+      executable(false),
+      share_read_only(false) {}
+
+SharedMemory::SharedMemory()
+    : mapped_size_(0), memory_(NULL), read_only_(false), requested_size_(0) {}
+
+SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
+    : shm_(handle),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.IsValid();
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  handle.Close();
+}
+
+// static
+size_t SharedMemory::GetHandleLimit() {
+  // This should be effectively unlimited on OS X.
+  return 10000;
+}
+
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.Duplicate();
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+// static
+bool SharedMemory::GetSizeFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle,
+    size_t* size) {
+  return handle.GetSize(size);
+}
+
+// Chromium mostly only uses the unique/private shmem as specified by
+// "name == L"". The exception is in the StatsTable.
+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(!shm_.IsValid());
+  if (options.size == 0) return false;
+
+  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  shm_ = SharedMemoryHandle(options.size);
+  requested_size_ = options.size;
+  return shm_.IsValid();
+}
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (!shm_.IsValid())
+    return false;
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+  if (memory_)
+    return false;
+
+  bool success = shm_.MapAt(offset, bytes, &memory_, read_only_);
+  if (success) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+                      (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  } else {
+    memory_ = NULL;
+  }
+
+  return success;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  mach_vm_deallocate(mach_task_self(),
+                     reinterpret_cast<mach_vm_address_t>(memory_),
+                     mapped_size_);
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return shm_;
+}
+
+void SharedMemory::Close() {
+  shm_.Close();
+  shm_ = SharedMemoryHandle();
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle /*process*/,
+                                        SharedMemoryHandle* new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  DCHECK(shm_.IsValid());
+
+  bool success = false;
+  switch (share_mode) {
+    case SHARE_CURRENT_MODE:
+      *new_handle = shm_.Duplicate();
+      success = true;
+      break;
+    case SHARE_READONLY:
+      success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
+      break;
+  }
+
+  if (success)
+    new_handle->SetOwnershipPassesToIPC(true);
+
+  if (close_self) {
+    Unmap();
+    Close();
+  }
+
+  return success;
+}
+
+}  // namespace base
diff --git a/libchrome/base/memory/shared_memory_mac_unittest.cc b/libchrome/base/memory/shared_memory_mac_unittest.cc
new file mode 100644
index 0000000..c7d20ec
--- /dev/null
+++ b/libchrome/base/memory/shared_memory_mac_unittest.cc
@@ -0,0 +1,459 @@
+// 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 <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <servers/bootstrap.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/command_line.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/process_handle.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+namespace {
+
+// Gets the current and maximum protection levels of the memory region.
+// Returns whether the operation was successful.
+// |current| and |max| are output variables only populated on success.
+bool GetProtections(void* address, size_t size, int* current, int* max) {
+  vm_region_info_t region_info;
+  mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
+  mach_vm_size_t mem_size = size;
+  vm_region_basic_info_64 basic_info;
+
+  region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
+  vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
+  memory_object_name_t memory_object;
+  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+
+  kern_return_t kr =
+      mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
+                     region_info, &count, &memory_object);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "Failed to get region info.";
+    return false;
+  }
+
+  *current = basic_info.protection;
+  *max = basic_info.max_protection;
+  return true;
+}
+
+// Creates a new SharedMemory with the given |size|, filled with 'a'.
+std::unique_ptr<SharedMemory> CreateSharedMemory(int size) {
+  SharedMemoryHandle shm(size);
+  if (!shm.IsValid()) {
+    LOG(ERROR) << "Failed to make SharedMemoryHandle";
+    return nullptr;
+  }
+  std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
+  shared_memory->Map(size);
+  memset(shared_memory->memory(), 'a', size);
+  return shared_memory;
+}
+
+static const std::string g_service_switch_name = "service_name";
+
+// Structs used to pass a mach port from client to server.
+struct MachSendPortMessage {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t data;
+};
+struct MachReceivePortMessage {
+  mach_msg_header_t header;
+  mach_msg_body_t body;
+  mach_msg_port_descriptor_t data;
+  mach_msg_trailer_t trailer;
+};
+
+// Makes the current process into a Mach Server with the given |service_name|.
+mach_port_t BecomeMachServer(const char* service_name) {
+  mach_port_t port;
+  kern_return_t kr = bootstrap_check_in(bootstrap_port, service_name, &port);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "BecomeMachServer";
+  return port;
+}
+
+// Returns the mach port for the Mach Server with the given |service_name|.
+mach_port_t LookupServer(const char* service_name) {
+  mach_port_t server_port;
+  kern_return_t kr =
+      bootstrap_look_up(bootstrap_port, service_name, &server_port);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "LookupServer";
+  return server_port;
+}
+
+mach_port_t MakeReceivingPort() {
+  mach_port_t client_port;
+  kern_return_t kr =
+      mach_port_allocate(mach_task_self(),         // our task is acquiring
+                         MACH_PORT_RIGHT_RECEIVE,  // a new receive right
+                         &client_port);            // with this name
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "MakeReceivingPort";
+  return client_port;
+}
+
+// Blocks until a mach message is sent to |server_port|. This mach message
+// must contain a mach port. Returns that mach port.
+mach_port_t ReceiveMachPort(mach_port_t port_to_listen_on) {
+  MachReceivePortMessage recv_msg;
+  mach_msg_header_t* recv_hdr = &(recv_msg.header);
+  recv_hdr->msgh_local_port = port_to_listen_on;
+  recv_hdr->msgh_size = sizeof(recv_msg);
+  kern_return_t kr =
+      mach_msg(recv_hdr,               // message buffer
+               MACH_RCV_MSG,           // option indicating service
+               0,                      // send size
+               recv_hdr->msgh_size,    // size of header + body
+               port_to_listen_on,      // receive name
+               MACH_MSG_TIMEOUT_NONE,  // no timeout, wait forever
+               MACH_PORT_NULL);        // no notification port
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "ReceiveMachPort";
+  mach_port_t other_task_port = recv_msg.data.name;
+  return other_task_port;
+}
+
+// Passes a copy of the send right of |port_to_send| to |receiving_port|.
+void SendMachPort(mach_port_t receiving_port,
+                  mach_port_t port_to_send,
+                  int disposition) {
+  MachSendPortMessage send_msg;
+  mach_msg_header_t* send_hdr;
+  send_hdr = &(send_msg.header);
+  send_hdr->msgh_bits =
+      MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
+  send_hdr->msgh_size = sizeof(send_msg);
+  send_hdr->msgh_remote_port = receiving_port;
+  send_hdr->msgh_local_port = MACH_PORT_NULL;
+  send_hdr->msgh_reserved = 0;
+  send_hdr->msgh_id = 0;
+  send_msg.body.msgh_descriptor_count = 1;
+  send_msg.data.name = port_to_send;
+  send_msg.data.disposition = disposition;
+  send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR;
+  int kr = mach_msg(send_hdr,               // message buffer
+                    MACH_SEND_MSG,          // option indicating send
+                    send_hdr->msgh_size,    // size of header + body
+                    0,                      // receive limit
+                    MACH_PORT_NULL,         // receive name
+                    MACH_MSG_TIMEOUT_NONE,  // no timeout, wait forever
+                    MACH_PORT_NULL);        // no notification port
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "SendMachPort";
+}
+
+std::string CreateRandomServiceName() {
+  return StringPrintf("SharedMemoryMacMultiProcessTest.%llu", RandUint64());
+}
+
+// Sets up the mach communication ports with the server. Returns a port to which
+// the server will send mach objects.
+mach_port_t CommonChildProcessSetUp() {
+  CommandLine cmd_line = *CommandLine::ForCurrentProcess();
+  std::string service_name =
+      cmd_line.GetSwitchValueASCII(g_service_switch_name);
+  mac::ScopedMachSendRight server_port(LookupServer(service_name.c_str()));
+  mach_port_t client_port = MakeReceivingPort();
+
+  // Send the port that this process is listening on to the server.
+  SendMachPort(server_port.get(), client_port, MACH_MSG_TYPE_MAKE_SEND);
+  return client_port;
+}
+
+// The number of active names in the current task's port name space.
+mach_msg_type_number_t GetActiveNameCount() {
+  mach_port_name_array_t name_array;
+  mach_msg_type_number_t names_count;
+  mach_port_type_array_t type_array;
+  mach_msg_type_number_t types_count;
+  kern_return_t kr = mach_port_names(mach_task_self(), &name_array,
+                                     &names_count, &type_array, &types_count);
+  MACH_CHECK(kr == KERN_SUCCESS, kr) << "GetActiveNameCount";
+  return names_count;
+}
+
+}  // namespace
+
+class SharedMemoryMacMultiProcessTest : public MultiProcessTest {
+ public:
+  SharedMemoryMacMultiProcessTest() {}
+
+  CommandLine MakeCmdLine(const std::string& procname) override {
+    CommandLine command_line = MultiProcessTest::MakeCmdLine(procname);
+    // Pass the service name to the child process.
+    command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
+    return command_line;
+  }
+
+  void SetUpChild(const std::string& name) {
+    // Make a random service name so that this test doesn't conflict with other
+    // similar tests.
+    service_name_ = CreateRandomServiceName();
+    server_port_.reset(BecomeMachServer(service_name_.c_str()));
+    child_process_ = SpawnChild(name);
+    client_port_.reset(ReceiveMachPort(server_port_.get()));
+  }
+
+  static const int s_memory_size = 99999;
+
+ protected:
+  std::string service_name_;
+
+  // A port on which the main process listens for mach messages from the child
+  // process.
+  mac::ScopedMachReceiveRight server_port_;
+
+  // A port on which the child process listens for mach messages from the main
+  // process.
+  mac::ScopedMachSendRight client_port_;
+
+  base::Process child_process_;
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryMacMultiProcessTest);
+};
+
+// Tests that content written to shared memory in the server process can be read
+// by the child process.
+TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) {
+  SetUpChild("MachBasedSharedMemoryClient");
+
+  std::unique_ptr<SharedMemory> shared_memory(
+      CreateSharedMemory(s_memory_size));
+
+  // Send the underlying memory object to the client process.
+  SendMachPort(client_port_.get(), shared_memory->handle().GetMemoryObject(),
+               MACH_MSG_TYPE_COPY_SEND);
+  int rv = -1;
+  ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
+      TestTimeouts::action_timeout(), &rv));
+  EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) {
+  mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
+  // The next mach port should be for a memory object.
+  mach_port_t memory_object = ReceiveMachPort(client_port.get());
+  SharedMemoryHandle shm(memory_object,
+                         SharedMemoryMacMultiProcessTest::s_memory_size,
+                         GetCurrentProcId());
+  SharedMemory shared_memory(shm, false);
+  shared_memory.Map(SharedMemoryMacMultiProcessTest::s_memory_size);
+  const char* start = static_cast<const char*>(shared_memory.memory());
+  for (int i = 0; i < SharedMemoryMacMultiProcessTest::s_memory_size; ++i) {
+    DCHECK_EQ(start[i], 'a');
+  }
+  return 0;
+}
+
+// Tests that mapping shared memory with an offset works correctly.
+TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) {
+  SetUpChild("MachBasedSharedMemoryWithOffsetClient");
+
+  SharedMemoryHandle shm(s_memory_size);
+  ASSERT_TRUE(shm.IsValid());
+  SharedMemory shared_memory(shm, false);
+  shared_memory.Map(s_memory_size);
+
+  size_t page_size = SysInfo::VMAllocationGranularity();
+  char* start = static_cast<char*>(shared_memory.memory());
+  memset(start, 'a', page_size);
+  memset(start + page_size, 'b', page_size);
+  memset(start + 2 * page_size, 'c', page_size);
+
+  // Send the underlying memory object to the client process.
+  SendMachPort(
+      client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND);
+  int rv = -1;
+  ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
+      TestTimeouts::action_timeout(), &rv));
+  EXPECT_EQ(0, rv);
+}
+
+MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) {
+  mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
+  // The next mach port should be for a memory object.
+  mach_port_t memory_object = ReceiveMachPort(client_port.get());
+  SharedMemoryHandle shm(memory_object,
+                         SharedMemoryMacMultiProcessTest::s_memory_size,
+                         GetCurrentProcId());
+  SharedMemory shared_memory(shm, false);
+  size_t page_size = SysInfo::VMAllocationGranularity();
+  shared_memory.MapAt(page_size, 2 * page_size);
+  const char* start = static_cast<const char*>(shared_memory.memory());
+  for (size_t i = 0; i < page_size; ++i) {
+    DCHECK_EQ(start[i], 'b');
+  }
+  for (size_t i = page_size; i < 2 * page_size; ++i) {
+    DCHECK_EQ(start[i], 'c');
+  }
+  return 0;
+}
+
+// Tests that duplication and closing has the right effect on Mach reference
+// counts.
+TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) {
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  // Making a new SharedMemoryHandle increments the name count.
+  SharedMemoryHandle shm(s_memory_size);
+  ASSERT_TRUE(shm.IsValid());
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Duplicating the SharedMemoryHandle increments the ref count, but doesn't
+  // make a new name.
+  shm.Duplicate();
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Closing the SharedMemoryHandle decrements the ref count. The first time has
+  // no effect.
+  shm.Close();
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Closing the SharedMemoryHandle decrements the ref count. The second time
+  // destroys the port.
+  shm.Close();
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that Mach shared memory can be mapped and unmapped.
+TEST_F(SharedMemoryMacMultiProcessTest, MachUnmapMap) {
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  std::unique_ptr<SharedMemory> shared_memory =
+      CreateSharedMemory(s_memory_size);
+  ASSERT_TRUE(shared_memory->Unmap());
+  ASSERT_TRUE(shared_memory->Map(s_memory_size));
+  shared_memory.reset();
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that passing a SharedMemoryHandle to a SharedMemory object also passes
+// ownership, and that destroying the SharedMemory closes the SharedMemoryHandle
+// as well.
+TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) {
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  // Making a new SharedMemoryHandle increments the name count.
+  SharedMemoryHandle shm(s_memory_size);
+  ASSERT_TRUE(shm.IsValid());
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Name count doesn't change when mapping the memory.
+  std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
+  shared_memory->Map(s_memory_size);
+  EXPECT_EQ(active_name_count + 1, GetActiveNameCount());
+
+  // Destroying the SharedMemory object frees the resource.
+  shared_memory.reset();
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that the read-only flag works.
+TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) {
+  std::unique_ptr<SharedMemory> shared_memory(
+      CreateSharedMemory(s_memory_size));
+
+  SharedMemoryHandle shm2 = shared_memory->handle().Duplicate();
+  ASSERT_TRUE(shm2.IsValid());
+  SharedMemory shared_memory2(shm2, true);
+  shared_memory2.Map(s_memory_size);
+  ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
+}
+
+// Tests that the method ShareToProcess() works.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcess) {
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  {
+    std::unique_ptr<SharedMemory> shared_memory(
+        CreateSharedMemory(s_memory_size));
+
+    SharedMemoryHandle shm2;
+    ASSERT_TRUE(shared_memory->ShareToProcess(GetCurrentProcId(), &shm2));
+    ASSERT_TRUE(shm2.IsValid());
+    SharedMemory shared_memory2(shm2, true);
+    shared_memory2.Map(s_memory_size);
+
+    ASSERT_EQ(0, memcmp(shared_memory->memory(), shared_memory2.memory(),
+                        s_memory_size));
+  }
+
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that the method ShareReadOnlyToProcess() creates a memory object that
+// is read only.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonly) {
+  std::unique_ptr<SharedMemory> shared_memory(
+      CreateSharedMemory(s_memory_size));
+
+  // Check the protection levels.
+  int current_prot, max_prot;
+  ASSERT_TRUE(GetProtections(shared_memory->memory(),
+                             shared_memory->mapped_size(), &current_prot,
+                             &max_prot));
+  ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot);
+  ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot);
+
+  // Make a new memory object.
+  SharedMemoryHandle shm2;
+  ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
+  ASSERT_TRUE(shm2.IsValid());
+
+  // Mapping with |readonly| set to |false| should fail.
+  SharedMemory shared_memory2(shm2, false);
+  shared_memory2.Map(s_memory_size);
+  ASSERT_EQ(nullptr, shared_memory2.memory());
+
+  // Now trying mapping with |readonly| set to |true|.
+  SharedMemory shared_memory3(shm2.Duplicate(), true);
+  shared_memory3.Map(s_memory_size);
+  ASSERT_NE(nullptr, shared_memory3.memory());
+
+  // Check the protection levels.
+  ASSERT_TRUE(GetProtections(shared_memory3.memory(),
+                             shared_memory3.mapped_size(), &current_prot,
+                             &max_prot));
+  ASSERT_EQ(VM_PROT_READ, current_prot);
+  ASSERT_EQ(VM_PROT_READ, max_prot);
+
+  // The memory should still be readonly, since the underlying memory object
+  // is readonly.
+  ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
+}
+
+// Tests that the method ShareReadOnlyToProcess() doesn't leak.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonlyLeak) {
+  mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+  {
+    std::unique_ptr<SharedMemory> shared_memory(
+        CreateSharedMemory(s_memory_size));
+
+    SharedMemoryHandle shm2;
+    ASSERT_TRUE(
+        shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
+    ASSERT_TRUE(shm2.IsValid());
+
+    // Intentionally map with |readonly| set to |false|.
+    SharedMemory shared_memory2(shm2, false);
+    shared_memory2.Map(s_memory_size);
+  }
+
+  EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+}  //  namespace base
diff --git a/libchrome/base/memory/shared_memory_posix.cc b/libchrome/base/memory/shared_memory_posix.cc
new file mode 100644
index 0000000..7e94223
--- /dev/null
+++ b/libchrome/base/memory/shared_memory_posix.cc
@@ -0,0 +1,505 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <sys/mman.h>
+#include <sys/stat.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/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 "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#include "third_party/ashmem/ashmem.h"
+#elif defined(__ANDROID__)
+#include <cutils/ashmem.h>
+#endif
+
+namespace base {
+
+namespace {
+
+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) && !defined(__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) &&  !defined(__ANDROID__)
+}
+
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+    : name_deprecated(nullptr),
+      open_existing_deprecated(false),
+      size(0),
+      executable(false),
+      share_read_only(false) {}
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(const 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() {
+  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 (IGNORE_EINTR(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) && !defined(__ANDROID__)
+// static
+bool SharedMemory::GetSizeFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle,
+    size_t* size) {
+  struct stat st;
+  if (fstat(handle.fd, &st) != 0)
+    return false;
+  if (st.st_size < 0)
+    return false;
+  *size = st.st_size;
+  return true;
+}
+
+// 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 == nullptr) {
+    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.";
+      }
+    }
+    return false;
+  }
+
+  return PrepareMapFile(std::move(fp), std::move(readonly_fd));
+}
+
+// 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(std::move(fp), std::move(readonly_fd));
+}
+#endif  // !defined(OS_ANDROID) && !defined(__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) || defined(__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 (IGNORE_EINTR(close(mapped_file_)) < 0)
+      PLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+  if (readonly_mapped_file_ > 0) {
+    if (IGNORE_EINTR(close(readonly_mapped_file_)) < 0)
+      PLOG(ERROR) << "close";
+    readonly_mapped_file_ = -1;
+  }
+}
+
+#if !defined(OS_ANDROID) && !defined(__ANDROID__)
+bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
+  DCHECK_EQ(-1, mapped_file_);
+  DCHECK_EQ(-1, readonly_mapped_file_);
+  if (fp == nullptr)
+    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(GOOGLE_CHROME_BUILD)
+  std::string name_base = std::string("com.google.Chrome");
+#else
+  std::string name_base = std::string("org.chromium.Chromium");
+#endif
+  *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
+  return true;
+}
+#endif  // !defined(OS_ANDROID) && !defined(__ANDROID__)
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle,
+                                        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) {
+    if (close_self) {
+      Unmap();
+      Close();
+    }
+    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/libchrome/base/memory/shared_memory_unittest.cc b/libchrome/base/memory/shared_memory_unittest.cc
new file mode 100644
index 0000000..f29865c
--- /dev/null
+++ b/libchrome/base/memory/shared_memory_unittest.cc
@@ -0,0 +1,697 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/macros.h"
+#include "base/memory/shared_memory_handle.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 "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#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
+
+namespace base {
+
+namespace {
+
+#if !defined(OS_MACOSX)
+// 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_t id) : id_(id) {}
+  ~MultipleThreadMain() override {}
+
+  static void CleanUp() {
+    SharedMemory memory;
+    memory.Delete(s_test_name_);
+  }
+
+  // PlatformThread::Delegate interface.
+  void ThreadMain() override {
+    const uint32_t 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(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_t id_;
+
+  static const char s_test_name_[];
+
+  DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
+};
+
+const char MultipleThreadMain::s_test_name_[] =
+    "SharedMemoryOpenThreadTest";
+#endif  // !defined(OS_MACOSX)
+
+}  // namespace
+
+// Android/Mac doesn't support SharedMemory::Open/Delete/
+// CreateNamedDeprecated(openExisting=true)
+#if !defined(OS_ANDROID) && !defined(OS_MACOSX)
+TEST(SharedMemoryTest, OpenClose) {
+  const uint32_t 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_t kDataSize = 1024;
+  const uint32_t 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 + 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 + 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  // !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
+// 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());
+}
+
+#if !defined(OS_MACOSX)
+// 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) {
+  const int kNumThreads = 5;
+
+  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];
+    std::unique_ptr<PlatformThreadHandle[]> thread_handles;
+    std::unique_ptr<MultipleThreadMain* []> thread_delegates;
+
+    thread_handles.reset(new PlatformThreadHandle[numthreads]);
+    thread_delegates.reset(new MultipleThreadMain*[numthreads]);
+
+    // Spawn the threads.
+    for (int16_t 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();
+}
+#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_t kDataSize = 8192;
+
+  std::unique_ptr<SharedMemory[]> memories(new SharedMemory[count]);
+  std::unique_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();
+  }
+}
+
+// The Mach functionality is tested in shared_memory_mac_unittest.cc.
+#if !(defined(OS_MACOSX) && !defined(OS_IOS))
+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)
+  int handle_fd = SharedMemory::GetFdFromSharedMemoryHandle(handle);
+  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.GetHandle(), FILE_MAP_WRITE, 0, 0, 0))
+      << "Shouldn't be able to map memory writable.";
+
+  HANDLE temp_handle;
+  BOOL rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(),
+                              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)
+    win::ScopedHandle writable_handle(temp_handle);
+  rv = ::DuplicateHandle(GetCurrentProcess(), handle.GetHandle(),
+                         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)
+    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)
+}
+#endif  // !(defined(OS_MACOSX) && !defined(OS_IOS))
+
+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));
+#if defined(OS_WIN)
+  ASSERT_TRUE(shared_handle.OwnershipPassesToIPC());
+#endif
+  SharedMemory shared(shared_handle, /*readonly=*/false);
+
+  ASSERT_TRUE(shared.Map(contents.size()));
+  EXPECT_EQ(
+      contents,
+      StringPiece(static_cast<const char*>(shared.memory()), contents.size()));
+
+  shared_handle = SharedMemoryHandle();
+  ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+#if defined(OS_WIN)
+  ASSERT_TRUE(shared_handle.OwnershipPassesToIPC());
+#endif
+  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_t));
+  const size_t kCount = SysInfo::VMAllocationGranularity();
+  const size_t kDataSize = kCount * sizeof(uint32_t);
+
+  SharedMemory memory;
+  ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
+  uint32_t* ptr = static_cast<uint32_t*>(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_t);
+  ptr = static_cast<uint32_t*>(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_t 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) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+// 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_t 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_t 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 =
+      SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
+  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_t 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 fd = SharedMemory::GetFdFromSharedMemoryHandle(shared_memory.handle());
+  struct stat shm_stat;
+  EXPECT_EQ(0, fstat(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) && !(defined(OS_MACOSX) && !defined(OS_IOS))
+
+// 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_WIN)
+TEST(SharedMemoryTest, UnsafeImageSection) {
+  const char kTestSectionName[] = "UnsafeImageSection";
+  wchar_t path[MAX_PATH];
+  EXPECT_GT(::GetModuleFileName(nullptr, path, arraysize(path)), 0U);
+
+  // Map the current executable image to save us creating a new PE file on disk.
+  base::win::ScopedHandle file_handle(::CreateFile(
+      path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr));
+  EXPECT_TRUE(file_handle.IsValid());
+  base::win::ScopedHandle section_handle(
+      ::CreateFileMappingA(file_handle.Get(), nullptr,
+                           PAGE_READONLY | SEC_IMAGE, 0, 0, kTestSectionName));
+  EXPECT_TRUE(section_handle.IsValid());
+
+  // Check direct opening by name, from handle and duplicated from handle.
+  SharedMemory shared_memory_open;
+  EXPECT_TRUE(shared_memory_open.Open(kTestSectionName, true));
+  EXPECT_FALSE(shared_memory_open.Map(1));
+  EXPECT_EQ(nullptr, shared_memory_open.memory());
+
+  SharedMemory shared_memory_handle_local(
+      SharedMemoryHandle(section_handle.Take(), ::GetCurrentProcessId()), true);
+  EXPECT_FALSE(shared_memory_handle_local.Map(1));
+  EXPECT_EQ(nullptr, shared_memory_handle_local.memory());
+
+  // Check that a handle without SECTION_QUERY also can't be mapped as it can't
+  // be checked.
+  SharedMemory shared_memory_handle_dummy;
+  SharedMemoryCreateOptions options;
+  options.size = 0x1000;
+  EXPECT_TRUE(shared_memory_handle_dummy.Create(options));
+  HANDLE handle_no_query;
+  EXPECT_TRUE(::DuplicateHandle(
+      ::GetCurrentProcess(), shared_memory_handle_dummy.handle().GetHandle(),
+      ::GetCurrentProcess(), &handle_no_query, FILE_MAP_READ, FALSE, 0));
+  SharedMemory shared_memory_handle_no_query(
+      SharedMemoryHandle(handle_no_query, ::GetCurrentProcessId()), true);
+  EXPECT_FALSE(shared_memory_handle_no_query.Map(1));
+  EXPECT_EQ(nullptr, shared_memory_handle_no_query.memory());
+}
+#endif  // defined(OS_WIN)
+
+// iOS does not allow multiple processes.
+// Android ashmem does not support named shared memory.
+// Mac SharedMemory does not support named shared memory. crbug.com/345734
+#if !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+// 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;
+    SharedMemory memory;
+    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    rv = memory.Map(s_data_size_);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    int* ptr = static_cast<int*>(memory.memory());
+
+    // This runs concurrently in multiple processes. Writes need to be atomic.
+    subtle::Barrier_AtomicIncrement(ptr, 1);
+    memory.Close();
+    return errors;
+  }
+
+  static const char s_test_name_[];
+  static const uint32_t s_data_size_;
+};
+
+const char SharedMemoryProcessTest::s_test_name_[] = "MPMem";
+const uint32_t SharedMemoryProcessTest::s_data_size_ = 1024;
+
+TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) {
+  const int kNumTasks = 5;
+
+  SharedMemoryProcessTest::CleanUp();
+
+  // Create a shared memory region. Set the first word to 0.
+  SharedMemory memory;
+  bool rv = memory.CreateNamedDeprecated(s_test_name_, true, s_data_size_);
+  ASSERT_TRUE(rv);
+  rv = memory.Map(s_data_size_);
+  ASSERT_TRUE(rv);
+  int* ptr = static_cast<int*>(memory.memory());
+  *ptr = 0;
+
+  // Start |kNumTasks| processes, each of which atomically increments the first
+  // word by 1.
+  Process processes[kNumTasks];
+  for (int index = 0; index < kNumTasks; ++index) {
+    processes[index] = SpawnChild("SharedMemoryTestMain");
+    ASSERT_TRUE(processes[index].IsValid());
+  }
+
+  // Check that each process exited correctly.
+  int exit_code = 0;
+  for (int index = 0; index < kNumTasks; ++index) {
+    EXPECT_TRUE(processes[index].WaitForExit(&exit_code));
+    EXPECT_EQ(0, exit_code);
+  }
+
+  // Check that the shared memory region reflects |kNumTasks| increments.
+  ASSERT_EQ(kNumTasks, *ptr);
+
+  memory.Close();
+  SharedMemoryProcessTest::CleanUp();
+}
+
+MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
+  return SharedMemoryProcessTest::TaskTestMain();
+}
+#endif  // !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+
+}  // namespace base
diff --git a/libchrome/base/memory/singleton.cc b/libchrome/base/memory/singleton.cc
new file mode 100644
index 0000000..f68ecaa
--- /dev/null
+++ b/libchrome/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/libchrome/base/memory/singleton.h b/libchrome/base/memory/singleton.h
new file mode 100644
index 0000000..79e4441
--- /dev/null
+++ b/libchrome/base/memory/singleton.h
@@ -0,0 +1,284 @@
+// 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/macros.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);
+
+class DeleteTraceLogForTesting;
+
+}  // namespace internal
+
+
+// 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 (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() { subtle::NoBarrier_Store(&dead_, 0); }
+
+ private:
+  static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+  // Signal the object was already deleted, so it is not revived.
+  static subtle::Atomic32 dead_;
+};
+
+template <typename Type>
+AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+    StaticMemorySingletonTraits<Type>::buffer_;
+template <typename Type>
+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 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 internal::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)
+      ThreadRestrictions::AssertSingletonAllowed();
+#endif
+
+    // The load has acquire memory ordering as the thread which reads the
+    // instance_ pointer must acquire visibility over the singleton data.
+    subtle::AtomicWord value = subtle::Acquire_Load(&instance_);
+    if (value != 0 && value != internal::kBeingCreatedMarker) {
+      return reinterpret_cast<Type*>(value);
+    }
+
+    // Object isn't created yet, maybe we will get to create it, let's try...
+    if (subtle::Acquire_CompareAndSwap(&instance_, 0,
+                                       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.
+      subtle::Release_Store(&instance_,
+                            reinterpret_cast<subtle::AtomicWord>(newval));
+
+      if (newval != NULL && Traits::kRegisterAtExit)
+        AtExitManager::RegisterCallback(OnExit, NULL);
+
+      return newval;
+    }
+
+    // We hit a race. Wait for the other thread to complete it.
+    value = 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*>(subtle::NoBarrier_Load(&instance_)));
+    instance_ = 0;
+  }
+  static subtle::AtomicWord instance_;
+};
+
+template <typename Type, typename Traits, typename DifferentiatingType>
+subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0;
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SINGLETON_H_
diff --git a/libchrome/base/memory/singleton_objc.h b/libchrome/base/memory/singleton_objc.h
new file mode 100644
index 0000000..6df3f77
--- /dev/null
+++ b/libchrome/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/libchrome/base/memory/singleton_unittest.cc b/libchrome/base/memory/singleton_unittest.cc
new file mode 100644
index 0000000..a15145c
--- /dev/null
+++ b/libchrome/base/memory/singleton_unittest.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2012 The Chromium Authors. 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 "base/at_exit.h"
+#include "base/memory/singleton.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
+              "object must be deleted on process exit");
+
+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_;
+}
+
+
+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;
+
+  {
+    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());
+
+  {
+    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_t>* align4 =
+      AlignedTestSingleton<int32_t>::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);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/libchrome/base/memory/weak_ptr.cc b/libchrome/base/memory/weak_ptr.cc
new file mode 100644
index 0000000..4e77b04
--- /dev/null
+++ b/libchrome/base/memory/weak_ptr.cc
@@ -0,0 +1,81 @@
+// 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() {
+}
+
+WeakReference::WeakReference(WeakReference&& other) = default;
+
+WeakReference::WeakReference(const WeakReference& other) = default;
+
+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/libchrome/base/memory/weak_ptr.h b/libchrome/base/memory/weak_ptr.h
new file mode 100644
index 0000000..3544439
--- /dev/null
+++ b/libchrome/base/memory/weak_ptr.h
@@ -0,0 +1,361 @@
+// Copyright (c) 2012 The Chromium 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 nullptr) 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:
+//    Controller() : weak_factory_(this) {}
+//    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.
+//
+// If all WeakPtr objects are destroyed or invalidated then the factory is
+// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be
+// destroyed, or new WeakPtr objects may be used, from a different sequence.
+//
+// Thus, at least one WeakPtr object must exist and have been dereferenced on
+// the correct thread to enforce that other WeakPtr objects will enforce they
+// are used on the desired thread.
+
+#ifndef BASE_MEMORY_WEAK_PTR_H_
+#define BASE_MEMORY_WEAK_PTR_H_
+
+#include <cstddef>
+#include <type_traits>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.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();
+
+  WeakReference(WeakReference&& other);
+  WeakReference(const WeakReference& other);
+  WeakReference& operator=(WeakReference&& other) = default;
+  WeakReference& operator=(const WeakReference& other) = default;
+
+  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();
+
+  WeakPtrBase(const WeakPtrBase& other) = default;
+  WeakPtrBase(WeakPtrBase&& other) = default;
+  WeakPtrBase& operator=(const WeakPtrBase& other) = default;
+  WeakPtrBase& operator=(WeakPtrBase&& other) = default;
+
+ 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) {
+    static_assert(
+        std::is_base_of<internal::SupportsWeakPtrBase, Derived>::value,
+        "AsWeakPtr argument must inherit 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_(nullptr) {}
+
+  WeakPtr(std::nullptr_t) : ptr_(nullptr) {}
+
+  // Allow conversion from U to T provided U "is a" T. Note that this
+  // is separate from the (implicit) copy and move constructors.
+  template <typename U>
+  WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) {
+  }
+  template <typename U>
+  WeakPtr(WeakPtr<U>&& other)
+      : WeakPtrBase(std::move(other)), ptr_(other.ptr_) {}
+
+  T* get() const { return ref_.is_valid() ? ptr_ : nullptr; }
+
+  T& operator*() const {
+    DCHECK(get() != nullptr);
+    return *get();
+  }
+  T* operator->() const {
+    DCHECK(get() != nullptr);
+    return get();
+  }
+
+  void reset() {
+    ref_ = internal::WeakReference();
+    ptr_ = nullptr;
+  }
+
+  // Allow conditionals to test validity, e.g. if (weak_ptr) {...};
+  explicit operator bool() const { return get() != nullptr; }
+
+ private:
+  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 nullptr).
+  T* ptr_;
+};
+
+// Allow callers to compare WeakPtrs against nullptr to test validity.
+template <class T>
+bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
+  return !(weak_ptr == nullptr);
+}
+template <class T>
+bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
+  return weak_ptr != nullptr;
+}
+template <class T>
+bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
+  return weak_ptr.get() == nullptr;
+}
+template <class T>
+bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
+  return weak_ptr == nullptr;
+}
+
+// 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_ = nullptr; }
+
+  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/libchrome/base/memory/weak_ptr_unittest.cc b/libchrome/base/memory/weak_ptr_unittest.cc
new file mode 100644
index 0000000..ebcf33c
--- /dev/null
+++ b/libchrome/base/memory/weak_ptr_unittest.cc
@@ -0,0 +1,681 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/location.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 {
+
+WeakPtr<int> PassThru(WeakPtr<int> ptr) {
+  return ptr;
+}
+
+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(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromTarget, arrow,
+                              target, &completion));
+    completion.Wait();
+  }
+
+  void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
+    WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromArrow, arrow,
+                              other, &completion));
+    completion.Wait();
+  }
+
+  void DeleteTarget(Target* object) {
+    WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+    task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
+    completion.Wait();
+  }
+
+  void CopyAndAssignArrow(Arrow* object) {
+    WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrow, object,
+                              &completion));
+    completion.Wait();
+  }
+
+  void CopyAndAssignArrowBase(Arrow* object) {
+    WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
+                              object, &completion));
+    completion.Wait();
+  }
+
+  void DeleteArrow(Arrow* object) {
+    WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+    task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
+    completion.Wait();
+  }
+
+  Target* DeRef(const Arrow* arrow) {
+    WaitableEvent completion(WaitableEvent::ResetPolicy::MANUAL,
+                             WaitableEvent::InitialState::NOT_SIGNALED);
+    Target* result = nullptr;
+    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, Move) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  WeakPtr<int> ptr2 = factory.GetWeakPtr();
+  WeakPtr<int> ptr3 = std::move(ptr2);
+  EXPECT_NE(ptr.get(), ptr2.get());
+  EXPECT_EQ(ptr.get(), ptr3.get());
+}
+
+TEST(WeakPtrFactoryTest, OutOfScope) {
+  WeakPtr<int> ptr;
+  EXPECT_EQ(nullptr, ptr.get());
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    ptr = factory.GetWeakPtr();
+  }
+  EXPECT_EQ(nullptr, 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(nullptr, a.get());
+  EXPECT_EQ(nullptr, b.get());
+}
+
+TEST(WeakPtrFactoryTest, MultipleStaged) {
+  WeakPtr<int> a;
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    a = factory.GetWeakPtr();
+    {
+      WeakPtr<int> b = factory.GetWeakPtr();
+    }
+    EXPECT_NE(nullptr, a.get());
+  }
+  EXPECT_EQ(nullptr, 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, ConstructFromNullptr) {
+  WeakPtr<int> ptr = PassThru(nullptr);
+  EXPECT_EQ(nullptr, ptr.get());
+}
+
+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(WeakPtrFactoryTest, BooleanTesting) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+
+  WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr();
+  EXPECT_TRUE(ptr_to_an_instance);
+  EXPECT_FALSE(!ptr_to_an_instance);
+
+  if (ptr_to_an_instance) {
+  } else {
+    ADD_FAILURE() << "Pointer to an instance should result in true.";
+  }
+
+  if (!ptr_to_an_instance) {  // check for operator!().
+    ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
+  }
+
+  WeakPtr<int> null_ptr;
+  EXPECT_FALSE(null_ptr);
+  EXPECT_TRUE(!null_ptr);
+
+  if (null_ptr) {
+    ADD_FAILURE() << "Null pointer should result in false.";
+  }
+
+  if (!null_ptr) {  // check for operator!().
+  } else {
+    ADD_FAILURE() << "Null pointer should result in !x being true.";
+  }
+}
+
+TEST(WeakPtrFactoryTest, ComparisonToNull) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+
+  WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr();
+  EXPECT_NE(nullptr, ptr_to_an_instance);
+  EXPECT_NE(ptr_to_an_instance, nullptr);
+
+  WeakPtr<int> null_ptr;
+  EXPECT_EQ(null_ptr, nullptr);
+  EXPECT_EQ(nullptr, null_ptr);
+}
+
+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(nullptr, 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(nullptr, 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.
+  std::unique_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.
+  std::unique_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;
+  std::unique_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(nullptr, 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(nullptr, 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";
+
+  std::unique_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";
+
+  std::unique_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";
+
+  std::unique_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/libchrome/base/memory/weak_ptr_unittest.nc b/libchrome/base/memory/weak_ptr_unittest.nc
new file mode 100644
index 0000000..9b1226b
--- /dev/null
+++ b/libchrome/base/memory/weak_ptr_unittest.nc
@@ -0,0 +1,141 @@
+// Copyright (c) 2012 The Chromium 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 "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
+#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 \*'"]
+
+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 \*'"]
+
+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 \*'"]
+
+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 \*'"]
+
+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 \*'"]
+
+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 must inherit 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 must inherit from SupportsWeakPtr\""]
+
+void WontCompile() {
+  DerivedUnrelated f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_AMBIGUOUS_ANCESTORS)  // [r"fatal error: use of undeclared identifier 'AsWeakPtrImpl'"]
+
+void WontCompile() {
+  MultiplyDerivedProducer f;
+  WeakPtr<MultiplyDerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#endif
+
+}
diff --git a/libchrome/base/message_loop/incoming_task_queue.cc b/libchrome/base/message_loop/incoming_task_queue.cc
new file mode 100644
index 0000000..bca1d52
--- /dev/null
+++ b/libchrome/base/message_loop/incoming_task_queue.cc
@@ -0,0 +1,200 @@
+// 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/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+// 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
+  (void)type;  // Avoid an unused warning.
+  return false;
+#endif
+}
+
+TimeTicks 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;
+}
+
+}  // 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();
+
+  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)) {
+    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() {
+  base::subtle::AutoWriteLock lock(message_loop_lock_);
+  message_loop_ = NULL;
+}
+
+void IncomingTaskQueue::StartScheduling() {
+  bool schedule_work;
+  {
+    AutoLock lock(incoming_queue_lock_);
+    DCHECK(!is_ready_for_scheduling_);
+    DCHECK(!message_loop_scheduled_);
+    is_ready_for_scheduling_ = true;
+    schedule_work = !incoming_queue_.empty();
+  }
+  if (schedule_work) {
+    DCHECK(message_loop_);
+    // Don't need to lock |message_loop_lock_| here because this function is
+    // called by MessageLoop on its thread.
+    message_loop_->ScheduleWork();
+  }
+}
+
+IncomingTaskQueue::~IncomingTaskQueue() {
+  // Verify that WillDestroyCurrentMessageLoop() has been called.
+  DCHECK(!message_loop_);
+}
+
+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.
+
+  // Ensures |message_loop_| isn't destroyed while running.
+  base::subtle::AutoReadLock hold_message_loop(message_loop_lock_);
+
+  if (!message_loop_) {
+    pending_task->task.Reset();
+    return false;
+  }
+
+  bool schedule_work = false;
+  {
+    AutoLock hold(incoming_queue_lock_);
+
+#if defined(OS_WIN)
+    if (pending_task->is_high_res)
+      ++high_res_task_count_;
+#endif
+
+    // Initialize the sequence number. The sequence number is used for delayed
+    // tasks (to facilitate 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(std::move(*pending_task));
+
+    if (is_ready_for_scheduling_ &&
+        (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) {
+      schedule_work = true;
+      // 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;
+    }
+  }
+
+  // Wake up the message loop and schedule work. This is done outside
+  // |incoming_queue_lock_| because signaling the message loop may cause this
+  // thread to be switched. If |incoming_queue_lock_| is held, any other thread
+  // that wants to post a task will be blocked until this thread switches back
+  // in and releases |incoming_queue_lock_|.
+  if (schedule_work)
+    message_loop_->ScheduleWork();
+
+  return true;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/message_loop/incoming_task_queue.h b/libchrome/base/message_loop/incoming_task_queue.h
new file mode 100644
index 0000000..aff71d2
--- /dev/null
+++ b/libchrome/base/message_loop/incoming_task_queue.h
@@ -0,0 +1,115 @@
+// 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/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/pending_task.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/read_write_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();
+
+ private:
+  friend class RefCountedThreadSafe<IncomingTaskQueue>;
+  virtual ~IncomingTaskQueue();
+
+  // 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, except
+  // |message_loop_|.
+  base::Lock incoming_queue_lock_;
+
+  // Lock that protects |message_loop_| to prevent it from being deleted while a
+  // task is being posted.
+  base::subtle::ReadWriteLock message_loop_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/libchrome/base/message_loop/message_loop.cc b/libchrome/base/message_loop/message_loop.cc
new file mode 100644
index 0000000..54369a9
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop.cc
@@ -0,0 +1,778 @@
+// 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 <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.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/threading/thread_id_name_manager.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+#include "build/build_config.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 initialize an array of pairs.  In this case,
+// our pair consists of the expressions value, and the "stringized" version
+// of the expression (i.e., the expression 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)
+
+std::unique_ptr<MessagePump> ReturnPump(std::unique_ptr<MessagePump> pump) {
+  return pump;
+}
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+
+MessageLoop::TaskObserver::TaskObserver() {
+}
+
+MessageLoop::TaskObserver::~TaskObserver() {
+}
+
+MessageLoop::DestructionObserver::~DestructionObserver() {
+}
+
+MessageLoop::NestingObserver::~NestingObserver() {}
+
+//------------------------------------------------------------------------------
+
+MessageLoop::MessageLoop(Type type)
+    : MessageLoop(type, MessagePumpFactoryCallback()) {
+  BindToCurrentThread();
+}
+
+MessageLoop::MessageLoop(std::unique_ptr<MessagePump> pump)
+    : MessageLoop(TYPE_CUSTOM, Bind(&ReturnPump, Passed(&pump))) {
+  BindToCurrentThread();
+}
+
+MessageLoop::~MessageLoop() {
+  // If |pump_| is non-null, this message loop has been bound and should be the
+  // current one on this thread. Otherwise, this loop is being destructed before
+  // it was bound to a thread, so a different message loop (or no loop at all)
+  // may be current.
+  DCHECK((pump_ && current() == this) || (!pump_ && current() != this));
+
+  // 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;
+  unbound_task_runner_ = NULL;
+  task_runner_ = NULL;
+
+  // OK, now make it so that no one can find us.
+  if (current() == this)
+    lazy_tls_ptr.Pointer()->Set(nullptr);
+}
+
+// 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
+std::unique_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 std::unique_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 std::unique_ptr<MessagePump>()
+#else
+#define MESSAGE_PUMP_UI std::unique_ptr<MessagePump>(new MessagePumpForUI())
+#endif
+
+#if defined(OS_MACOSX)
+  // Use an OS native runloop on Mac to support timer coalescing.
+#define MESSAGE_PUMP_DEFAULT \
+  std::unique_ptr<MessagePump>(new MessagePumpCFRunLoop())
+#else
+#define MESSAGE_PUMP_DEFAULT \
+  std::unique_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 std::unique_ptr<MessagePump>(new MessagePumpForIO());
+
+#if defined(OS_ANDROID)
+  if (type == MessageLoop::TYPE_JAVA)
+    return std::unique_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::AddNestingObserver(NestingObserver* observer) {
+  DCHECK_EQ(this, current());
+  nesting_observers_.AddObserver(observer);
+}
+
+void MessageLoop::RemoveNestingObserver(NestingObserver* observer) {
+  DCHECK_EQ(this, current());
+  nesting_observers_.RemoveObserver(observer);
+}
+
+void MessageLoop::PostTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  task_runner_->PostTask(from_here, task);
+}
+
+void MessageLoop::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  task_runner_->PostDelayedTask(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_->QuitWhenIdle();
+  } else {
+    NOTREACHED() << "Must be inside Run to call QuitWhenIdle";
+  }
+}
+
+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 incoming queue, since we don't want to lock the work
+  // queue.
+  return incoming_task_queue_->IsIdleForTesting();
+}
+
+//------------------------------------------------------------------------------
+
+// static
+std::unique_ptr<MessageLoop> MessageLoop::CreateUnbound(
+    Type type,
+    MessagePumpFactoryCallback pump_factory) {
+  return WrapUnique(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),
+      pump_factory_(pump_factory),
+      message_histogram_(NULL),
+      run_loop_(NULL),
+      incoming_task_queue_(new internal::IncomingTaskQueue(this)),
+      unbound_task_runner_(
+          new internal::MessageLoopTaskRunner(incoming_task_queue_)),
+      task_runner_(unbound_task_runner_),
+      thread_id_(kInvalidThreadId) {
+  // If type is TYPE_CUSTOM non-null pump_factory must be given.
+  DCHECK(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();
+  unbound_task_runner_->BindToCurrentThread();
+  unbound_task_runner_ = nullptr;
+  SetThreadTaskRunnerHandle();
+  {
+    // Save the current thread's ID for potential use by other threads
+    // later from GetThreadName().
+    thread_id_ = PlatformThread::CurrentId();
+    subtle::MemoryBarrier();
+  }
+}
+
+std::string MessageLoop::GetThreadName() const {
+  if (thread_id_ == kInvalidThreadId) {
+    // |thread_id_| may already have been initialized but this thread might not
+    // have received the update yet.
+    subtle::MemoryBarrier();
+    DCHECK_NE(kInvalidThreadId, thread_id_);
+  }
+  return ThreadIdNameManager::GetInstance()->GetName(thread_id_);
+}
+
+void MessageLoop::SetTaskRunner(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  DCHECK_EQ(this, current());
+  DCHECK(task_runner->BelongsToCurrentThread());
+  DCHECK(!unbound_task_runner_);
+  task_runner_ = std::move(task_runner);
+  SetThreadTaskRunnerHandle();
+}
+
+void MessageLoop::SetThreadTaskRunnerHandle() {
+  DCHECK_EQ(this, current());
+  // Clear the previous thread task runner first, because only one can exist at
+  // a time.
+  thread_task_runner_handle_.reset();
+  thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_));
+}
+
+void MessageLoop::RunHandler() {
+  DCHECK_EQ(this, current());
+  StartHistogrammer();
+  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 =
+      std::move(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);
+
+  TRACE_TASK_EXECUTION("MessageLoop::RunTask", pending_task);
+
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    WillProcessTask(pending_task));
+  task_annotator_.RunTask("MessageLoop::PostTask", pending_task);
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    DidProcessTask(pending_task));
+
+  nestable_tasks_allowed_ = true;
+}
+
+bool MessageLoop::DeferOrRunPendingTask(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(std::move(pending_task));
+  return false;
+}
+
+void MessageLoop::AddToDelayedWorkQueue(PendingTask pending_task) {
+  // Move to the delayed work queue.
+  delayed_work_queue_.push(std::move(pending_task));
+}
+
+bool MessageLoop::DeletePendingTasks() {
+  bool did_work = !work_queue_.empty();
+  while (!work_queue_.empty()) {
+    PendingTask pending_task = std::move(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(std::move(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();
+}
+
+#if defined(OS_WIN)
+bool MessageLoop::MessagePumpWasSignaled() {
+  return pump_->WasSignaled();
+}
+#endif
+
+//------------------------------------------------------------------------------
+// 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()) {
+    std::string thread_name = GetThreadName();
+    DCHECK(!thread_name.empty());
+    message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription(
+        "MsgLoop:" + thread_name, kLeastNonZeroMessageId, kMaxMessageId,
+        kNumberOfDistinctMessagesDisplayed,
+        HistogramBase::kHexRangePrintingFlag, event_descriptions_);
+  }
+#endif
+}
+
+void MessageLoop::HistogramEvent(int event) {
+#if !defined(OS_NACL)
+  if (message_histogram_)
+    message_histogram_->Add(event);
+#endif
+}
+
+void MessageLoop::NotifyBeginNestedLoop() {
+  FOR_EACH_OBSERVER(NestingObserver, nesting_observers_,
+                    OnBeginNestedMessageLoop());
+}
+
+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 = std::move(work_queue_.front());
+      work_queue_.pop();
+      if (!pending_task.delayed_run_time.is_null()) {
+        int sequence_num = pending_task.sequence_num;
+        TimeTicks delayed_run_time = pending_task.delayed_run_time;
+        AddToDelayedWorkQueue(std::move(pending_task));
+        // If we changed the topmost task, then it is time to reschedule.
+        if (delayed_work_queue_.top().sequence_num == sequence_num)
+          pump_->ScheduleDelayedWork(delayed_run_time);
+      } else {
+        if (DeferOrRunPendingTask(std::move(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 =
+      std::move(const_cast<PendingTask&>(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(std::move(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;
+}
+
+void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
+                                     void(*deleter)(const void*),
+                                     const void* object) {
+  task_runner()->PostNonNestableTask(from_here, Bind(deleter, object));
+}
+
+void MessageLoop::ReleaseSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*releaser)(const void*),
+    const void* object) {
+  task_runner()->PostNonNestableTask(from_here, Bind(releaser, object));
+}
+
+#if !defined(OS_NACL)
+//------------------------------------------------------------------------------
+// MessageLoopForUI
+
+MessageLoopForUI::MessageLoopForUI(std::unique_ptr<MessagePump> pump)
+    : MessageLoop(TYPE_UI, Bind(&ReturnPump, Passed(&pump))) {}
+
+#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
+
+MessageLoopForIO::MessageLoopForIO() : MessageLoop(TYPE_IO) {}
+
+#if !defined(OS_NACL_SFI)
+
+#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/libchrome/base/message_loop/message_loop.h b/libchrome/base/message_loop/message_loop.h
new file mode 100644
index 0000000..ac522cf
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop.h
@@ -0,0 +1,700 @@
+// 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 <memory>
+#include <queue>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/debug/task_annotator.h"
+#include "base/gtest_prod_util.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/incoming_task_queue.h"
+#include "base/message_loop/message_loop_task_runner.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"
+#include "build/build_config.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(std::unique_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 std::unique_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 std::unique_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);
+
+  // A NestingObserver is notified when a nested message loop begins. The
+  // observers are notified before the first task is processed.
+  class BASE_EXPORT NestingObserver {
+   public:
+    virtual void OnBeginNestedMessageLoop() = 0;
+
+   protected:
+    virtual ~NestingObserver();
+  };
+
+  void AddNestingObserver(NestingObserver* observer);
+  void RemoveNestingObserver(NestingObserver* 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);
+
+  // 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();
+
+  // 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();
+
+  // 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_; }
+
+  // Returns the name of the thread this message loop is bound to.
+  // This function is only valid when this message loop is running and
+  // BindToCurrentThread has already been called.
+  std::string GetThreadName() const;
+
+  // Gets the TaskRunner associated with this message loop.
+  const scoped_refptr<SingleThreadTaskRunner>& task_runner() {
+    return task_runner_;
+  }
+
+  // Sets a new TaskRunner for this message loop. The message loop must already
+  // have been bound to a thread prior to this call, and the task runner must
+  // belong to that thread. Note that changing the task runner will also affect
+  // the ThreadTaskRunnerHandle for the target thread. Must be called on the
+  // thread to which the message loop is bound.
+  void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
+
+  // Enables or disables the recursive task processing. This happens in the case
+  // of recursive message loops. Some unwanted message loops may occur when
+  // using common controls or printer functions. By default, recursive task
+  // processing is disabled.
+  //
+  // Please use |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 executes it.
+  // - The task #1 implicitly starts 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);
+
+  // 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);
+
+#if defined(OS_WIN)
+  // TODO (stanisc): crbug.com/596190: Remove this after the signaling issue
+  // has been investigated.
+  // This should be used for diagnostic only. If message pump wake-up mechanism
+  // is based on auto-reset event this call would reset the event to unset
+  // state.
+  bool MessagePumpWasSignaled();
+#endif
+
+  //----------------------------------------------------------------------------
+ protected:
+  std::unique_ptr<MessagePump> pump_;
+
+  using MessagePumpFactoryCallback = Callback<std::unique_ptr<MessagePump>()>;
+
+  // Common protected constructor. Other constructors delegate the
+  // initialization to this constructor.
+  // A subclass can invoke this constructor to create a message_loop of a
+  // specific type with a custom loop. The implementation does not call
+  // BindToCurrentThread. If this constructor is invoked directly by a subclass,
+  // then the subclass must subsequently bind the message loop.
+  MessageLoop(Type type, MessagePumpFactoryCallback pump_factory);
+
+  // Configure various members and bind this message loop to the current thread.
+  void BindToCurrentThread();
+
+ private:
+  friend class RunLoop;
+  friend class internal::IncomingTaskQueue;
+  friend class ScheduleWorkTest;
+  friend class Thread;
+  FRIEND_TEST_ALL_PREFIXES(MessageLoopTest, DeleteUnboundLoop);
+
+  // 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.
+  static std::unique_ptr<MessageLoop> CreateUnbound(
+      Type type,
+      MessagePumpFactoryCallback pump_factory);
+
+  // Sets the ThreadTaskRunnerHandle for the current thread to point to the
+  // task runner for this message loop.
+  void SetThreadTaskRunnerHandle();
+
+  // 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(PendingTask pending_task);
+
+  // Adds the pending task to delayed_work_queue_.
+  void AddToDelayedWorkQueue(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);
+
+  // Notify observers that a nested message loop is starting.
+  void NotifyBeginNestedLoop();
+
+  // MessagePump::Delegate methods:
+  bool DoWork() override;
+  bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
+  bool DoIdleWork() 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_;
+
+  ObserverList<NestingObserver> nesting_observers_;
+
+  // A recursion block that prevents accidentally running additional tasks when
+  // insider a (accidentally induced?) nested message pump.
+  bool nestable_tasks_allowed_;
+
+  // 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_;
+
+  // 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_;
+
+  // A task runner which we haven't bound to a thread yet.
+  scoped_refptr<internal::MessageLoopTaskRunner> unbound_task_runner_;
+
+  // The task runner associated with this message loop.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+  std::unique_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
+
+  // Id of the thread this message loop is bound to.
+  PlatformThreadId thread_id_;
+
+  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) {
+  }
+
+  explicit MessageLoopForUI(std::unique_ptr<MessagePump> pump);
+
+  // Returns the MessageLoopForUI of the current thread.
+  static MessageLoopForUI* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK(loop);
+    DCHECK(loop->IsType(MessageLoop::TYPE_UI));
+    return static_cast<MessageLoopForUI*>(loop);
+  }
+
+  static bool IsCurrent() {
+    MessageLoop* loop = MessageLoop::current();
+    return loop && loop->IsType(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.
+static_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();
+
+  // Returns the MessageLoopForIO of the current thread.
+  static MessageLoopForIO* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK(loop) << "Can't call MessageLoopForIO::current() when no message "
+                    "loop was created for this thread. Use "
+                    " MessageLoop::current() or MessageLoopForIO::IsCurrent().";
+    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;
+#elif defined(OS_IOS)
+  typedef MessagePumpIOSForIO::Watcher Watcher;
+  typedef MessagePumpIOSForIO::FileDescriptorWatcher
+      FileDescriptorWatcher;
+
+  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;
+
+  enum Mode {
+    WATCH_READ = MessagePumpLibevent::WATCH_READ,
+    WATCH_WRITE = MessagePumpLibevent::WATCH_WRITE,
+    WATCH_READ_WRITE = MessagePumpLibevent::WATCH_READ_WRITE
+  };
+#endif
+
+#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.
+static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+              "MessageLoopForIO should not have extra member variables");
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_
diff --git a/libchrome/base/message_loop/message_loop_task_runner.cc b/libchrome/base/message_loop/message_loop_task_runner.cc
new file mode 100644
index 0000000..c9b5ffe
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop_task_runner.cc
@@ -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/message_loop/message_loop_task_runner.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/incoming_task_queue.h"
+
+namespace base {
+namespace internal {
+
+MessageLoopTaskRunner::MessageLoopTaskRunner(
+    scoped_refptr<IncomingTaskQueue> incoming_queue)
+    : incoming_queue_(incoming_queue), valid_thread_id_(kInvalidThreadId) {
+}
+
+void MessageLoopTaskRunner::BindToCurrentThread() {
+  AutoLock lock(valid_thread_id_lock_);
+  DCHECK_EQ(kInvalidThreadId, valid_thread_id_);
+  valid_thread_id_ = PlatformThread::CurrentId();
+}
+
+bool MessageLoopTaskRunner::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 MessageLoopTaskRunner::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 MessageLoopTaskRunner::RunsTasksOnCurrentThread() const {
+  AutoLock lock(valid_thread_id_lock_);
+  return valid_thread_id_ == PlatformThread::CurrentId();
+}
+
+MessageLoopTaskRunner::~MessageLoopTaskRunner() {
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/libchrome/base/message_loop/message_loop_task_runner.h b/libchrome/base/message_loop/message_loop_task_runner.h
new file mode 100644
index 0000000..5e70b12
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop_task_runner.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_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/pending_task.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+class IncomingTaskQueue;
+
+// A stock implementation of SingleThreadTaskRunner that is created and managed
+// by a MessageLoop. For now a MessageLoopTaskRunner can only be created as
+// part of a MessageLoop.
+class BASE_EXPORT MessageLoopTaskRunner : public SingleThreadTaskRunner {
+ public:
+  explicit MessageLoopTaskRunner(
+      scoped_refptr<IncomingTaskQueue> incoming_queue);
+
+  // Initialize this message loop task runner on the current thread.
+  void BindToCurrentThread();
+
+  // SingleThreadTaskRunner 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<MessageLoopTaskRunner>;
+  ~MessageLoopTaskRunner() 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(MessageLoopTaskRunner);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
diff --git a/libchrome/base/message_loop/message_loop_task_runner_unittest.cc b/libchrome/base/message_loop/message_loop_task_runner_unittest.cc
new file mode 100644
index 0000000..cabd250
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop_task_runner_unittest.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_loop_task_runner.h"
+
+#include <memory>
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_task_runner.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class MessageLoopTaskRunnerTest : public testing::Test {
+ public:
+  MessageLoopTaskRunnerTest()
+      : current_loop_(new MessageLoop()),
+        task_thread_("task_thread"),
+        thread_sync_(WaitableEvent::ResetPolicy::MANUAL,
+                     WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+  void DeleteCurrentMessageLoop() { current_loop_.reset(); }
+
+ protected:
+  void SetUp() override {
+    // Use SetUp() instead of the constructor to avoid posting a task to a
+    // partially constructed object.
+    task_thread_.Start();
+
+    // Allow us to pause the |task_thread_|'s MessageLoop.
+    task_thread_.message_loop()->task_runner()->PostTask(
+        FROM_HERE, Bind(&MessageLoopTaskRunnerTest::BlockTaskThreadHelper,
+                        Unretained(this)));
+  }
+
+  void TearDown() override {
+    // Make sure the |task_thread_| is not blocked, and stop the thread
+    // fully before destruction 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;
+
+  std::unique_ptr<MessageLoop> current_loop_;
+  Thread task_thread_;
+
+ private:
+  base::WaitableEvent thread_sync_;
+};
+
+StaticAtomicSequenceNumber MessageLoopTaskRunnerTest::g_order;
+
+TEST_F(MessageLoopTaskRunnerTest, 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_.task_runner()->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(MessageLoopTaskRunnerTest, 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 task runner to a dead MessageLoop.
+  scoped_refptr<SingleThreadTaskRunner> task_runner =
+      task_thread_.task_runner();
+  UnblockTaskThread();
+  task_thread_.Stop();
+
+  ASSERT_FALSE(
+      task_runner->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(MessageLoopTaskRunnerTest, 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_->task_runner()->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(MessageLoopTaskRunnerTest, 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_.task_runner()->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
+  // already been deleted in order to perform this test.  See
+  // http://crbug.com/86301.
+}
+
+class MessageLoopTaskRunnerThreadingTest : public testing::Test {
+ public:
+  void Release() const {
+    AssertOnIOThread();
+    Quit();
+  }
+
+  void Quit() const {
+    loop_.task_runner()->PostTask(FROM_HERE,
+                                  MessageLoop::QuitWhenIdleClosure());
+  }
+
+  void AssertOnIOThread() const {
+    ASSERT_TRUE(io_thread_->task_runner()->BelongsToCurrentThread());
+    ASSERT_EQ(io_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+  }
+
+  void AssertOnFileThread() const {
+    ASSERT_TRUE(file_thread_->task_runner()->BelongsToCurrentThread());
+    ASSERT_EQ(file_thread_->task_runner(), ThreadTaskRunnerHandle::Get());
+  }
+
+ protected:
+  void SetUp() override {
+    io_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_IO"));
+    file_thread_.reset(new Thread("MessageLoopTaskRunnerThreadingTest_File"));
+    io_thread_->Start();
+    file_thread_->Start();
+  }
+
+  void TearDown() override {
+    io_thread_->Stop();
+    file_thread_->Stop();
+  }
+
+  static void BasicFunction(MessageLoopTaskRunnerThreadingTest* test) {
+    test->AssertOnFileThread();
+    test->Quit();
+  }
+
+  static void AssertNotRun() { FAIL() << "Callback Should not get executed."; }
+
+  class DeletedOnFile {
+   public:
+    explicit DeletedOnFile(MessageLoopTaskRunnerThreadingTest* test)
+        : test_(test) {}
+
+    ~DeletedOnFile() {
+      test_->AssertOnFileThread();
+      test_->Quit();
+    }
+
+   private:
+    MessageLoopTaskRunnerThreadingTest* test_;
+  };
+
+  std::unique_ptr<Thread> io_thread_;
+  std::unique_ptr<Thread> file_thread_;
+
+ private:
+  mutable MessageLoop loop_;
+};
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Release) {
+  EXPECT_TRUE(io_thread_->task_runner()->ReleaseSoon(FROM_HERE, this));
+  RunLoop().Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, Delete) {
+  DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
+  EXPECT_TRUE(
+      file_thread_->task_runner()->DeleteSoon(FROM_HERE, deleted_on_file));
+  RunLoop().Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTask) {
+  EXPECT_TRUE(file_thread_->task_runner()->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::BasicFunction,
+                      Unretained(this))));
+  RunLoop().Run();
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadExits) {
+  std::unique_ptr<Thread> test_thread(
+      new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+  test_thread->Start();
+  scoped_refptr<SingleThreadTaskRunner> task_runner =
+      test_thread->task_runner();
+  test_thread->Stop();
+
+  bool ret = task_runner->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+TEST_F(MessageLoopTaskRunnerThreadingTest, PostTaskAfterThreadIsDeleted) {
+  scoped_refptr<SingleThreadTaskRunner> task_runner;
+  {
+    std::unique_ptr<Thread> test_thread(
+        new Thread("MessageLoopTaskRunnerThreadingTest_Dummy"));
+    test_thread->Start();
+    task_runner = test_thread->task_runner();
+  }
+  bool ret = task_runner->PostTask(
+      FROM_HERE, Bind(&MessageLoopTaskRunnerThreadingTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+}  // namespace base
diff --git a/libchrome/base/message_loop/message_loop_test.cc b/libchrome/base/message_loop/message_loop_test.cc
new file mode 100644
index 0000000..1ab946f
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop_test.cc
@@ -0,0 +1,1055 @@
+// 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 <stddef.h>
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+  // Add tests to message loop
+  scoped_refptr<Foo> foo(new Foo());
+  std::string a("a"), b("b"), c("c"), d("d");
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&Foo::Test0, foo.get()));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&Foo::Test1ConstRef, foo.get(), a));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&Foo::Test1Ptr, foo.get(), &b));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&Foo::Test1Int, foo.get(), 100));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&Foo::Test2Ptr, foo.get(), &a, &c));
+  MessageLoop::current()->task_runner()->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()->task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  RunLoop().Run();
+
+  EXPECT_EQ(foo->test_count(), 105);
+  EXPECT_EQ(foo->result(), "abacad");
+}
+
+void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  // Test that PostDelayedTask results in a delayed task.
+
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  int num_tasks = 1;
+  Time run_time;
+
+  loop.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks), kDelay);
+
+  Time time_before_run = Time::Now();
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  // Test that two tasks with different delays run in the right order.
+  int num_tasks = 2;
+  Time run_time1, run_time2;
+
+  loop.task_runner()->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.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  RunLoop().Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 < run_time1);
+}
+
+void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  // 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.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay);
+  loop.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay);
+
+  RunLoop().Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time1 < run_time2);
+}
+
+void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  // 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.task_runner()->PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks));
+  loop.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time time_before_run = Time::Now();
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  // 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.task_runner()->PostTask(
+        FROM_HERE, Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
+
+  loop.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(1));
+
+  RunLoop().Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 > run_time1);
+}
+
+void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  // 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.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+      TimeDelta::FromSeconds(1000));
+  loop.task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time start_time = Time::Now();
+
+  RunLoop().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()->task_runner()->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;
+  {
+    std::unique_ptr<MessagePump> pump(factory());
+    MessageLoop loop(std::move(pump));
+    loop.task_runner()->PostTask(
+        FROM_HERE, Bind(&RecordDeletionProbe::Run,
+                        new RecordDeletionProbe(NULL, &a_was_deleted)));
+    // TODO(ajwong): Do we really need 1000ms here?
+    loop.task_runner()->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;
+  {
+    std::unique_ptr<MessagePump> pump(factory());
+    MessageLoop loop(std::move(pump));
+    // 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.task_runner()->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()->task_runner()->PostTask(FROM_HERE,
+                                                    Bind(&NestingFunc, depth));
+
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+    RunLoop().Run();
+  }
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+void RunTest_Nesting(MessagePumpFactory factory) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  int depth = 100;
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&NestingFunc, &depth));
+  RunLoop().Run();
+  EXPECT_EQ(depth, 0);
+}
+
+// A NestingObserver that tracks the number of nested message loop starts it
+// has seen.
+class TestNestingObserver : public MessageLoop::NestingObserver {
+ public:
+  TestNestingObserver() {}
+  ~TestNestingObserver() override {}
+
+  int begin_nested_loop_count() const { return begin_nested_loop_count_; }
+
+  // MessageLoop::NestingObserver:
+  void OnBeginNestedMessageLoop() override { begin_nested_loop_count_++; }
+
+ private:
+  int begin_nested_loop_count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(TestNestingObserver);
+};
+
+void ExpectOneBeginNestedLoop(TestNestingObserver* observer) {
+  EXPECT_EQ(1, observer->begin_nested_loop_count());
+}
+
+// Starts a nested message loop.
+void RunNestedLoop(TestNestingObserver* observer,
+                   const Closure& quit_outer_loop) {
+  // The nested loop hasn't started yet.
+  EXPECT_EQ(0, observer->begin_nested_loop_count());
+
+  MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+  RunLoop nested_loop;
+  // Verify that by the time the first task is run the observer has seen the
+  // message loop begin.
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&ExpectOneBeginNestedLoop, observer));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  nested_loop.QuitClosure());
+  nested_loop.Run();
+
+  // Quitting message loops doesn't change the begin count.
+  EXPECT_EQ(1, observer->begin_nested_loop_count());
+
+  quit_outer_loop.Run();
+}
+
+// Tests that a NestingObserver is notified when a nested message loop begins.
+void RunTest_NestingObserver(MessagePumpFactory factory) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop outer_loop(std::move(pump));
+
+  // Observe the outer loop for nested message loops beginning.
+  TestNestingObserver nesting_observer;
+  outer_loop.AddNestingObserver(&nesting_observer);
+
+  // Post a task that runs a nested message loop.
+  outer_loop.task_runner()->PostTask(FROM_HERE,
+                                     Bind(&RunNestedLoop, &nesting_observer,
+                                          outer_loop.QuitWhenIdleClosure()));
+  RunLoop().Run();
+
+  outer_loop.RemoveNestingObserver(&nesting_observer);
+}
+
+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()->task_runner()->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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, false));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, false));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&QuitFunc, &order, 3));
+
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false));
+  MessageLoop::current()->task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 3), TimeDelta::FromMilliseconds(5));
+  MessageLoop::current()->task_runner()->PostDelayedTask(
+      FROM_HERE, Bind(&QuitFunc, &order, 4), TimeDelta::FromMilliseconds(5));
+
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&QuitFunc, &order, 3));
+
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  MessageLoop::current()->task_runner()->PostNonNestableTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&QuitFunc, &order, 3));
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&FuncThatPumps, &order, 1));
+  MessageLoop::current()->task_runner()->PostNonNestableTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 5));
+  MessageLoop::current()->task_runner()->PostNonNestableTask(
+      FROM_HERE,
+      Bind(&QuitFunc, &order, 6));
+
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 4));  // never runs
+
+  RunLoop().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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  outer_run_loop.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->task_runner()->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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->task_runner()->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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+  RunLoop bogus_run_loop;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  bogus_run_loop.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  outer_run_loop.QuitClosure());
+  MessageLoop::current()->task_runner()->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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_loop1;
+  RunLoop nested_loop2;
+  RunLoop nested_loop3;
+  RunLoop nested_loop4;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 5));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  outer_run_loop.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 6));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  nested_loop1.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 7));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  nested_loop2.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 8));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  nested_loop3.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 9));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  nested_loop4.QuitClosure());
+  MessageLoop::current()->task_runner()->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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  run_loop.Quit();
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 1));  // never runs
+  MessageLoop::current()->task_runner()->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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  run_loop.QuitClosure());
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));  // never runs
+  MessageLoop::current()->task_runner()->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) {
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->task_runner()->PostTask(FROM_HERE,
+                                                  Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, run_loop.QuitClosure());  // has no affect
+  MessageLoop::current()->task_runner()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 4));
+  MessageLoop::current()->task_runner()->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()->task_runner()->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;
+  std::unique_ptr<MessagePump> pump(factory());
+  MessageLoop loop(std::move(pump));
+  loop.task_runner()->PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes));
+  RunLoop().Run();
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/libchrome/base/message_loop/message_loop_test.h b/libchrome/base/message_loop/message_loop_test.h
new file mode 100644
index 0000000..b7ae28e
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop_test.h
@@ -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.
+
+#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_NestingObserver(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);
+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, NonNestableDelayedInNestedLoop) { \
+    base::test::RunTest_NonNestableInNestedLoop(factory); \
+  } \
+  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/libchrome/base/message_loop/message_loop_unittest.cc b/libchrome/base/message_loop/message_loop_unittest.cc
new file mode 100644
index 0000000..52337e3
--- /dev/null
+++ b/libchrome/base/message_loop/message_loop_unittest.cc
@@ -0,0 +1,997 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.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/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_win.h"
+#include "base/process/memory.h"
+#include "base/strings/string16.h"
+#include "base/win/current_module.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 {
+
+std::unique_ptr<MessagePump> TypeDefaultMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_DEFAULT);
+}
+
+std::unique_ptr<MessagePump> TypeIOMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_IO);
+}
+
+std::unique_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(17u, 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(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(18u, 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(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()->task_runner()->PostTask(
+        FROM_HERE, Bind(&PostNTasksThenQuit, posts_remaining - 1));
+  } else {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+}
+
+#if defined(OS_WIN)
+
+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_));
+
+  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(static_cast<DWORD>(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 this 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(static_cast<DWORD>(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)
+// Additional set of tests for GPU version of UI message loop.
+RUN_MESSAGE_LOOP_TESTS(GPU, &MessagePumpForGpu::CreateMessagePumpForGpu);
+
+TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
+  RunTest_PostDelayedTask_SharedTimer_SubPump();
+}
+
+// This test occasionally hangs. See 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.task_runner()->PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumPosts));
+  RunLoop().Run();
+  loop.RemoveTaskObserver(&observer);
+
+  EXPECT_EQ(kNumPosts, observer.num_tasks_started());
+  EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
+}
+
+#if defined(OS_WIN)
+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->task_runner()->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()->task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  RunLoop().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()->QuitWhenIdle();
+    break;
+  }
+  return 0;
+}
+
+TEST(MessageLoopTest, AlwaysHaveUserMessageWhenNesting) {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+  HINSTANCE instance = CURRENT_MODULE();
+  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)
+
+TEST(MessageLoopTest, SetTaskRunner) {
+  MessageLoop loop;
+  scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+
+  loop.SetTaskRunner(new_runner);
+  EXPECT_EQ(new_runner, loop.task_runner());
+  EXPECT_EQ(new_runner, ThreadTaskRunnerHandle::Get());
+}
+
+TEST(MessageLoopTest, OriginalRunnerWorks) {
+  MessageLoop loop;
+  scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+  scoped_refptr<SingleThreadTaskRunner> original_runner(loop.task_runner());
+  loop.SetTaskRunner(new_runner);
+
+  scoped_refptr<Foo> foo(new Foo());
+  original_runner->PostTask(FROM_HERE,
+                            Bind(&Foo::Test1ConstRef, foo.get(), "a"));
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, foo->test_count());
+}
+
+TEST(MessageLoopTest, DeleteUnboundLoop) {
+  // It should be possible to delete an unbound message loop on a thread which
+  // already has another active loop. This happens when thread creation fails.
+  MessageLoop loop;
+  std::unique_ptr<MessageLoop> unbound_loop(MessageLoop::CreateUnbound(
+      MessageLoop::TYPE_DEFAULT, MessageLoop::MessagePumpFactoryCallback()));
+  unbound_loop.reset();
+  EXPECT_EQ(&loop, MessageLoop::current());
+  EXPECT_EQ(loop.task_runner(), ThreadTaskRunnerHandle::Get());
+}
+
+TEST(MessageLoopTest, ThreadName) {
+  {
+    std::string kThreadName("foo");
+    MessageLoop loop;
+    PlatformThread::SetName(kThreadName);
+    EXPECT_EQ(kThreadName, loop.GetThreadName());
+  }
+
+  {
+    std::string kThreadName("bar");
+    base::Thread thread(kThreadName);
+    ASSERT_TRUE(thread.StartAndWaitForTesting());
+    EXPECT_EQ(kThreadName, thread.message_loop()->GetThreadName());
+  }
+}
+
+}  // namespace base
diff --git a/libchrome/base/message_loop/message_pump.cc b/libchrome/base/message_loop/message_pump.cc
new file mode 100644
index 0000000..2f740f2
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump.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/message_loop/message_pump.h"
+
+namespace base {
+
+MessagePump::MessagePump() {
+}
+
+MessagePump::~MessagePump() {
+}
+
+void MessagePump::SetTimerSlack(TimerSlack) {
+}
+
+#if defined(OS_WIN)
+bool MessagePump::WasSignaled() {
+  NOTREACHED();
+  return false;
+}
+#endif
+
+}  // namespace base
diff --git a/libchrome/base/message_loop/message_pump.h b/libchrome/base/message_loop/message_pump.h
new file mode 100644
index 0000000..af8ed41
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump.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_MESSAGE_LOOP_MESSAGE_PUMP_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
+
+#include "base/base_export.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;
+  };
+
+  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);
+
+#if defined(OS_WIN)
+  // TODO (stanisc): crbug.com/596190: Remove this after the signaling issue
+  // has been investigated.
+  // This should be used for diagnostic only. If message pump wake-up mechanism
+  // is based on auto-reset event this call would reset the event to unset
+  // state.
+  virtual bool WasSignaled();
+#endif
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
diff --git a/libchrome/base/message_loop/message_pump_default.cc b/libchrome/base/message_loop/message_pump_default.cc
new file mode 100644
index 0000000..3449aec
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump_default.cc
@@ -0,0 +1,115 @@
+// 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"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace base {
+
+MessagePumpDefault::MessagePumpDefault()
+    : keep_running_(true),
+      event_(WaitableEvent::ResetPolicy::AUTOMATIC,
+             WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+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 (delay > TimeDelta()) {
+#if defined(OS_WIN)
+        // TODO(stanisc): crbug.com/623223: Consider moving the OS_WIN specific
+        // logic into TimedWait implementation in waitable_event_win.cc.
+
+        // crbug.com/487724: on Windows, waiting for less than 1 ms results in
+        // returning from TimedWait promptly and spinning
+        // MessagePumpDefault::Run loop for up to 1 ms - until it is time to
+        // run a delayed task. |min_delay| is the minimum possible wait to
+        // to avoid the spinning.
+        constexpr TimeDelta min_delay = TimeDelta::FromMilliseconds(1);
+        do {
+          delay = std::max(delay, min_delay);
+          if (event_.TimedWait(delay))
+            break;
+
+          // TimedWait can time out earlier than the specified |delay| on
+          // Windows. It doesn't make sense to run the outer loop in that case
+          // because there isn't going to be any new work. It is less overhead
+          // to just go back to wait.
+          // In practice this inner wait loop might have up to 3 iterations.
+          delay = delayed_work_time_ - TimeTicks::Now();
+        } while (delay > TimeDelta());
+#else
+        event_.TimedWait(delay);
+#endif
+      } 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/libchrome/base/message_loop/message_pump_default.h b/libchrome/base/message_loop/message_pump_default.h
new file mode 100644
index 0000000..4cd7cd1
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump_default.h
@@ -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.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+
+#include "base/base_export.h"
+#include "base/macros.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/libchrome/base/message_loop/message_pump_glib.cc b/libchrome/base/message_loop/message_pump_glib.cc
new file mode 100644
index 0000000..fd23745
--- /dev/null
+++ b/libchrome/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 subsystems 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/libchrome/base/message_loop/message_pump_glib.h b/libchrome/base/message_loop/message_pump_glib.h
new file mode 100644
index 0000000..a2b54d8
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump_glib.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_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/macros.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.
+  std::unique_ptr<GPollFD> wakeup_gpollfd_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpGlib);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
diff --git a/libchrome/base/message_loop/message_pump_glib_unittest.cc b/libchrome/base/message_loop/message_pump_glib_unittest.cc
new file mode 100644
index 0000000..7ddd4f0
--- /dev/null
+++ b/libchrome/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/libchrome/base/message_loop/message_pump_libevent.cc b/libchrome/base/message_loop/message_pump_libevent.cc
new file mode 100644
index 0000000..5aa5567
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump_libevent.cc
@@ -0,0 +1,365 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <unistd.h>
+
+#include <memory>
+
+#include "base/auto_reset.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/observer_list.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/third_party/libevent/event.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.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 {
+
+MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
+    : event_(NULL),
+      pump_(NULL),
+      watcher_(NULL),
+      was_destroyed_(NULL) {
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
+  if (event_) {
+    StopWatchingFileDescriptor();
+  }
+  if (was_destroyed_) {
+    DCHECK(!*was_destroyed_);
+    *was_destroyed_ = true;
+  }
+}
+
+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*) {
+  // Since OnFileCanWriteWithoutBlocking() gets called first, it can stop
+  // watching the file descriptor.
+  if (!watcher_)
+    return;
+  watcher_->OnFileCanReadWithoutBlocking(fd);
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+    int fd,
+    MessagePumpLibevent*) {
+  DCHECK(watcher_);
+  watcher_->OnFileCanWriteWithoutBlocking(fd);
+}
+
+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;
+  }
+
+  std::unique_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;
+}
+
+// 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().
+  std::unique_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;
+}
+
+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) {
+  FileDescriptorWatcher* controller =
+      static_cast<FileDescriptorWatcher*>(context);
+  DCHECK(controller);
+  TRACE_EVENT1("toplevel", "MessagePumpLibevent::OnLibeventNotification",
+               "fd", fd);
+
+  MessagePumpLibevent* pump = controller->pump();
+  pump->processed_io_events_ = true;
+
+  if ((flags & (EV_READ | EV_WRITE)) == (EV_READ | EV_WRITE)) {
+    // Both callbacks will be called. It is necessary to check that |controller|
+    // is not destroyed.
+    bool controller_was_destroyed = false;
+    controller->was_destroyed_ = &controller_was_destroyed;
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+    if (!controller_was_destroyed)
+      controller->OnFileCanReadWithoutBlocking(fd, pump);
+    if (!controller_was_destroyed)
+      controller->was_destroyed_ = nullptr;
+  } else if (flags & EV_WRITE) {
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+  } else if (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/libchrome/base/message_loop/message_pump_libevent.h b/libchrome/base/message_loop/message_pump_libevent.h
new file mode 100644
index 0000000..76f882f
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump_libevent.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_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/message_loop/message_pump.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:
+  // 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_;
+    // If this pointer is non-NULL, the pointee is set to true in the
+    // destructor.
+    bool* was_destroyed_;
+
+    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);
+
+  // 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_;
+
+  ThreadChecker watch_file_descriptor_caller_checker_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
diff --git a/libchrome/base/message_loop/message_pump_mac.h b/libchrome/base/message_loop/message_pump_mac.h
new file mode 100644
index 0000000..14b8377
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump_mac.h
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 The Chromium 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 preferable.
+// 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 <CoreFoundation/CoreFoundation.h>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/timer_slack.h"
+#include "build/build_config.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/libchrome/base/message_loop/message_pump_mac.mm b/libchrome/base/message_loop/message_pump_mac.mm
new file mode 100644
index 0000000..95d1c5f
--- /dev/null
+++ b/libchrome/base/message_loop/message_pump_mac.mm
@@ -0,0 +1,782 @@
+// Copyright (c) 2012 The Chromium 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/libchrome/base/message_loop/timer_slack.h b/libchrome/base/message_loop/timer_slack.h
new file mode 100644
index 0000000..1ad6ca9
--- /dev/null
+++ b/libchrome/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/libchrome/base/metrics/OWNERS b/libchrome/base/metrics/OWNERS
new file mode 100644
index 0000000..feb8271
--- /dev/null
+++ b/libchrome/base/metrics/OWNERS
@@ -0,0 +1,2 @@
+asvitkine@chromium.org
+isherman@chromium.org
diff --git a/libchrome/base/metrics/bucket_ranges.cc b/libchrome/base/metrics/bucket_ranges.cc
new file mode 100644
index 0000000..084cdd3
--- /dev/null
+++ b/libchrome/base/metrics/bucket_ranges.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/metrics/bucket_ranges.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Static table of checksums for all possible 8 bit bytes.
+const uint32_t 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_t.  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_t Crc32(uint32_t 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_t 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_t>(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_t BucketRanges::CalculateChecksum() const {
+  // Seed checksum.
+  uint32_t checksum = static_cast<uint32_t>(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/libchrome/base/metrics/bucket_ranges.h b/libchrome/base/metrics/bucket_ranges.h
new file mode 100644
index 0000000..c356195
--- /dev/null
+++ b/libchrome/base/metrics/bucket_ranges.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.
+//
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include <limits.h>
+
+#include "base/base_export.h"
+#include "base/macros.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_t checksum() const { return checksum_; }
+  void set_checksum(uint32_t 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_t 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_t. Because we see a lot of
+  // noise on UMA dashboard.
+  uint32_t checksum_;
+
+  DISALLOW_COPY_AND_ASSIGN(BucketRanges);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Expose only for test.
+BASE_EXPORT extern const uint32_t kCrcTable[256];
+
+}  // namespace base
+
+#endif  // BASE_METRICS_BUCKET_RANGES_H_
diff --git a/libchrome/base/metrics/bucket_ranges_unittest.cc b/libchrome/base/metrics/bucket_ranges_unittest.cc
new file mode 100644
index 0000000..481054c
--- /dev/null
+++ b/libchrome/base/metrics/bucket_ranges_unittest.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.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_t checksum = i;
+    for (int j = 0; j < 8; ++j) {
+      const uint32_t kReversedPolynomial = 0xedb88320L;
+      if (checksum & 1)
+        checksum = kReversedPolynomial ^ (checksum >> 1);
+      else
+        checksum >>= 1;
+    }
+    EXPECT_EQ(kCrcTable[i], checksum);
+  }
+}
+
+}  // namespace
+}  // namespace base
diff --git a/libchrome/base/metrics/field_trial.cc b/libchrome/base/metrics/field_trial.cc
new file mode 100644
index 0000000..600b94e
--- /dev/null
+++ b/libchrome/base/metrics/field_trial.cc
@@ -0,0 +1,658 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// 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).
+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.
+const char kActivationMarker = '*';
+
+// 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;
+  Time out_time;
+  if (!Time::FromLocalExploded(exploded, &out_time)) {
+    // TODO(maksims): implement failure handling.
+    // We might just return |out_time|, which is Time(0).
+    NOTIMPLEMENTED();
+  }
+
+  return out_time;
+}
+
+// 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);
+}
+
+// Parses the --force-fieldtrials string |trials_string| into |entries|.
+// Returns true if the string was parsed correctly. On failure, the |entries|
+// array may end up being partially filled.
+bool ParseFieldTrialsString(const std::string& trials_string,
+                            std::vector<FieldTrial::State>* entries) {
+  const StringPiece trials_string_piece(trials_string);
+
+  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();
+
+    FieldTrial::State entry;
+    // Verify if the trial should be activated or not.
+    if (trials_string[next_item] == kActivationMarker) {
+      // Name cannot be only the indicator.
+      if (name_end - next_item == 1)
+        return false;
+      next_item++;
+      entry.activated = true;
+    }
+    entry.trial_name =
+        trials_string_piece.substr(next_item, name_end - next_item);
+    entry.group_name =
+        trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1);
+    next_item = group_name_end + 1;
+
+    entries->push_back(entry);
+  }
+  return true;
+}
+
+}  // namespace
+
+// statics
+const int FieldTrial::kNotFinalized = -1;
+const int FieldTrial::kDefaultGroupNumber = 0;
+bool FieldTrial::enable_benchmarking_ = false;
+
+int FieldTrialList::kNoExpirationYear = 0;
+
+//------------------------------------------------------------------------------
+// FieldTrial methods and members.
+
+FieldTrial::EntropyProvider::~EntropyProvider() {
+}
+
+FieldTrial::State::State() : activated(false) {}
+
+FieldTrial::State::State(const State& other) = default;
+
+FieldTrial::State::~State() {}
+
+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_;
+}
+
+const std::string& FieldTrial::GetGroupNameWithoutActivation() {
+  FinalizeGroupChoice();
+  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(State* field_trial_state) {
+  if (!enable_field_trial_)
+    return false;
+  FinalizeGroupChoice();
+  field_trial_state->trial_name = trial_name_;
+  field_trial_state->group_name = 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, NULL);
+}
+
+// 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_t randomization_seed,
+    int* default_group_number,
+    const FieldTrial::EntropyProvider* override_entropy_provider) {
+  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;
+        static_assert(
+            kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
+            "The 'non-conflicting' group number conflicts");
+        static_assert(kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
+                      "The 'non-conflicting' group number conflicts");
+        *default_group_number = kNonConflictingGroupNumber;
+      }
+    }
+    return existing_trial;
+  }
+
+  double entropy_value;
+  if (randomization_type == FieldTrial::ONE_TIME_RANDOMIZED) {
+    // If an override entropy provider is given, use it.
+    const FieldTrial::EntropyProvider* entropy_provider =
+        override_entropy_provider ? override_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& trial_name) {
+  if (!global_)
+    return NULL;
+  AutoLock auto_lock(global_->lock_);
+  return global_->PreLockedFind(trial_name);
+}
+
+// static
+int FieldTrialList::FindValue(const std::string& trial_name) {
+  FieldTrial* field_trial = Find(trial_name);
+  if (field_trial)
+    return field_trial->group();
+  return FieldTrial::kNotFinalized;
+}
+
+// static
+std::string FieldTrialList::FindFullName(const std::string& trial_name) {
+  FieldTrial* field_trial = Find(trial_name);
+  if (field_trial)
+    return field_trial->group_name();
+  return std::string();
+}
+
+// static
+bool FieldTrialList::TrialExists(const std::string& trial_name) {
+  return Find(trial_name) != NULL;
+}
+
+// static
+bool FieldTrialList::IsTrialActive(const std::string& trial_name) {
+  FieldTrial* field_trial = Find(trial_name);
+  FieldTrial::ActiveGroup active_group;
+  return field_trial && field_trial->GetActiveGroup(&active_group);
+}
+
+// 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::State 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);
+    trial.trial_name.AppendToString(output);
+    output->append(1, kPersistentStringSeparator);
+    trial.group_name.AppendToString(output);
+    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
+void FieldTrialList::GetActiveFieldTrialGroupsFromString(
+    const std::string& trials_string,
+    FieldTrial::ActiveGroups* active_groups) {
+  std::vector<FieldTrial::State> entries;
+  if (!ParseFieldTrialsString(trials_string, &entries))
+    return;
+
+  for (const auto& entry : entries) {
+    if (entry.activated) {
+      FieldTrial::ActiveGroup group;
+      group.trial_name = entry.trial_name.as_string();
+      group.group_name = entry.group_name.as_string();
+      active_groups->push_back(group);
+    }
+  }
+}
+
+// static
+bool FieldTrialList::CreateTrialsFromString(
+    const std::string& trials_string,
+    const std::set<std::string>& ignored_trial_names) {
+  DCHECK(global_);
+  if (trials_string.empty() || !global_)
+    return true;
+
+  std::vector<FieldTrial::State> entries;
+  if (!ParseFieldTrialsString(trials_string, &entries))
+    return false;
+
+  for (const auto& entry : entries) {
+    const std::string trial_name = entry.trial_name.as_string();
+    const std::string group_name = entry.group_name.as_string();
+
+    if (ContainsKey(ignored_trial_names, trial_name))
+      continue;
+
+    FieldTrial* trial = CreateFieldTrial(trial_name, group_name);
+    if (!trial)
+      return false;
+    if (entry.activated) {
+      // 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_);
+  CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
+  trial->AddRef();
+  trial->SetTrialRegistered();
+  global_->registered_[trial->trial_name()] = trial;
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/field_trial.h b/libchrome/base/metrics/field_trial.h
new file mode 100644
index 0000000..28a4606
--- /dev/null
+++ b/libchrome/base/metrics/field_trial.h
@@ -0,0 +1,531 @@
+// Copyright (c) 2012 The Chromium 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 <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/strings/string_piece.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_t 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 BASE_EXPORT State {
+    StringPiece trial_name;
+    StringPiece group_name;
+    bool activated;
+
+    State();
+    State(const State& other);
+    ~State();
+  };
+
+  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();
+
+  // Finalizes the group choice and returns the chosen group, but does not mark
+  // the trial as active - so its state will not be reported until group_name()
+  // or similar is called.
+  const std::string& GetGroupNameWithoutActivation();
+
+  // 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(State* field_trial_state);
+
+  // 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:
+  // 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). If
+  // |override_entropy_provider| is not null, then it will be used for
+  // randomization instead of the provider given when the FieldTrialList was
+  // instanciated.
+  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_t randomization_seed,
+      int* default_group_number,
+      const FieldTrial::EntropyProvider* override_entropy_provider);
+
+  // 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& trial_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& trial_name);
+
+  // Returns the group name chosen for the named trial, or the empty string if
+  // the trial does not exist. The first call of this function on a given field
+  // trial will mark it as active, so that its state will be reported with usage
+  // metrics, crashes, etc.
+  static std::string FindFullName(const std::string& trial_name);
+
+  // Returns true if the named trial has been registered.
+  static bool TrialExists(const std::string& trial_name);
+
+  // Returns true if the named trial exists and has been activated.
+  static bool IsTrialActive(const std::string& trial_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);
+
+  // Returns the field trials that are marked active in |trials_string|.
+  static void GetActiveFieldTrialGroupsFromString(
+      const std::string& trials_string,
+      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. Created field
+  // trials will be marked "used" for the purposes of active trial reporting
+  // if they are prefixed with |kActivationMarker|. Trial names in
+  // |ignored_trial_names| are ignored when parsing |trials_string|.
+  static bool CreateTrialsFromString(
+      const std::string& trials_string,
+      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_;
+
+  std::map<std::string, std::string> seen_states_;
+
+  // Entropy provider to be used for one-time randomized field trials. If NULL,
+  // one-time randomization is not supported.
+  std::unique_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/libchrome/base/metrics/field_trial_unittest.cc b/libchrome/base/metrics/field_trial_unittest.cc
new file mode 100644
index 0000000..00f351f
--- /dev/null
+++ b/libchrome/base/metrics/field_trial_unittest.cc
@@ -0,0 +1,1134 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include "base/build_time.h"
+#include "base/macros.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_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialTest);
+};
+
+// 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, GetActiveFieldTrialGroupsFromString) {
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroupsFromString("*A/X/B/Y/*C/Z",
+                                                      &active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("A", active_groups[0].trial_name);
+  EXPECT_EQ("X", active_groups[0].group_name);
+  EXPECT_EQ("C", active_groups[1].trial_name);
+  EXPECT_EQ("Z", active_groups[1].group_name);
+}
+
+TEST_F(FieldTrialTest, AllGroups) {
+  FieldTrial::State 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, GetGroupNameWithoutActivation) {
+  const char kTrialName[] = "TestTrial";
+  const char kSecondaryGroupName[] = "SecondaryGroup";
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->AppendGroup(kSecondaryGroupName, 50);
+
+  // The trial should start inactive.
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+
+  // Calling |GetGroupNameWithoutActivation()| should not activate the trial.
+  std::string group_name = trial->GetGroupNameWithoutActivation();
+  EXPECT_FALSE(group_name.empty());
+  EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
+
+  // Calling |group_name()| should activate it and return the same group name.
+  EXPECT_EQ(group_name, trial->group_name());
+  EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
+}
+
+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", nullptr);
+  EXPECT_EQ("", trial->group_name_internal());
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("Some name/Default some name/", save_string);
+  // Getting all states should have finalized the trial.
+  EXPECT_EQ("Default some name", trial->group_name_internal());
+  save_string.clear();
+
+  // Create a winning group.
+  trial = CreateFieldTrial("trial2", 10, "Default some name", nullptr);
+  trial->AppendGroup("Winner", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  FieldTrialList::AllStatesToString(&save_string);
+  EXPECT_EQ("Some name/Default some name/*trial2/Winner/", save_string);
+  save_string.clear();
+
+  // Create a second trial and winning group.
+  scoped_refptr<FieldTrial> trial2 =
+      CreateFieldTrial("xxx", 10, "Default xxx", nullptr);
+  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/Default some name/*trial2/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/Default some name/*trial2/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/",
+                                         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",
+                                                     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",
+                                                      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("MissingGroupName/",
+                                                      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("noname, only group/",
+                                                      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("/emptyname",
+                                                      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("*/emptyname",
+                                                      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,
+                                                     std::set<std::string>()));
+
+  // But it is an error to try to change to a different winner.
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString("Some name/Loser/",
+                                                      std::set<std::string>()));
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/Xyz/zyx/",
+                                                     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/", 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, CreateTrialsFromStringNotActiveObserver) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+
+  TestFieldTrialObserver observer;
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString("Abc/def/",
+                                                     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/",
+      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::IntToString(j), 1);
+
+    EXPECT_EQ(base::IntToString(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,
+                                                      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/libchrome/base/metrics/histogram.cc b/libchrome/base/metrics/histogram.cc
new file mode 100644
index 0000000..0d6287c
--- /dev/null
+++ b/libchrome/base/metrics/histogram.cc
@@ -0,0 +1,1191 @@
+// Copyright (c) 2012 The Chromium 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 <limits.h>
+#include <math.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/metrics_hashes.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_memory_allocator.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,
+                            uint32_t* bucket_count,
+                            uint32_t* range_checksum) {
+  if (!iter->ReadString(histogram_name) ||
+      !iter->ReadInt(flags) ||
+      !iter->ReadInt(declared_min) ||
+      !iter->ReadInt(declared_max) ||
+      !iter->ReadUInt32(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 any IPC flag.
+  *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
+
+  return true;
+}
+
+bool ValidateRangeChecksum(const HistogramBase& histogram,
+                           uint32_t 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 uint32_t Histogram::kBucketCount_MAX = 16384u;
+
+class Histogram::Factory {
+ public:
+  Factory(const std::string& name,
+          HistogramBase::Sample minimum,
+          HistogramBase::Sample maximum,
+          uint32_t bucket_count,
+          int32_t flags)
+    : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
+  virtual ~Factory() = default;
+
+  // Create histogram based on construction parameters. Caller takes
+  // ownership of the returned object.
+  HistogramBase* Build();
+
+ protected:
+  Factory(const std::string& name,
+          HistogramType histogram_type,
+          HistogramBase::Sample minimum,
+          HistogramBase::Sample maximum,
+          uint32_t bucket_count,
+          int32_t flags)
+    : name_(name),
+      histogram_type_(histogram_type),
+      minimum_(minimum),
+      maximum_(maximum),
+      bucket_count_(bucket_count),
+      flags_(flags) {}
+
+  // Create a BucketRanges structure appropriate for this histogram.
+  virtual BucketRanges* CreateRanges() {
+    BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
+    Histogram::InitializeBucketRanges(minimum_, maximum_, ranges);
+    return ranges;
+  }
+
+  // Allocate the correct Histogram object off the heap (in case persistent
+  // memory is not available).
+  virtual std::unique_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) {
+    return WrapUnique(new Histogram(name_, minimum_, maximum_, ranges));
+  }
+
+  // Perform any required datafill on the just-created histogram.  If
+  // overridden, be sure to call the "super" version -- this method may not
+  // always remain empty.
+  virtual void FillHistogram(HistogramBase* /*histogram*/) {}
+
+  // These values are protected (instead of private) because they need to
+  // be accessible to methods of sub-classes in order to avoid passing
+  // unnecessary parameters everywhere.
+  const std::string& name_;
+  const HistogramType histogram_type_;
+  HistogramBase::Sample minimum_;
+  HistogramBase::Sample maximum_;
+  uint32_t bucket_count_;
+  int32_t flags_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
+HistogramBase* Histogram::Factory::Build() {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    const BucketRanges* created_ranges = CreateRanges();
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
+
+    // In most cases, the bucket-count, minimum, and maximum values are known
+    // when the code is written and so are passed in explicitly. In other
+    // cases (such as with a CustomHistogram), they are calculated dynamically
+    // at run-time. In the latter case, those ctor parameters are zero and
+    // the results extracted from the result of CreateRanges().
+    if (bucket_count_ == 0) {
+      bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count());
+      minimum_ = registered_ranges->range(1);
+      maximum_ = registered_ranges->range(bucket_count_ - 1);
+    }
+
+    // Try to create the histogram using a "persistent" allocator. As of
+    // 2016-02-25, the availability of such is controlled by a base::Feature
+    // that is off by default. If the allocator doesn't exist or if
+    // allocating from it fails, code below will allocate the histogram from
+    // the process heap.
+    PersistentHistogramAllocator::Reference histogram_ref = 0;
+    std::unique_ptr<HistogramBase> tentative_histogram;
+    PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
+    if (allocator) {
+      tentative_histogram = allocator->AllocateHistogram(
+          histogram_type_,
+          name_,
+          minimum_,
+          maximum_,
+          registered_ranges,
+          flags_,
+          &histogram_ref);
+    }
+
+    // Handle the case where no persistent allocator is present or the
+    // persistent allocation fails (perhaps because it is full).
+    if (!tentative_histogram) {
+      DCHECK(!histogram_ref);  // Should never have been set.
+      DCHECK(!allocator);  // Shouldn't have failed.
+      flags_ &= ~HistogramBase::kIsPersistent;
+      tentative_histogram = HeapAlloc(registered_ranges);
+      tentative_histogram->SetFlags(flags_);
+    }
+
+    FillHistogram(tentative_histogram.get());
+
+    // Register this histogram with the StatisticsRecorder. Keep a copy of
+    // the pointer value to tell later whether the locally created histogram
+    // was registered or deleted. The type is "void" because it could point
+    // to released memory after the following line.
+    const void* tentative_histogram_ptr = tentative_histogram.get();
+    histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
+        tentative_histogram.release());
+
+    // Persistent histograms need some follow-up processing.
+    if (histogram_ref) {
+      allocator->FinalizeHistogram(histogram_ref,
+                                   histogram == tentative_histogram_ptr);
+    }
+
+    // Update report on created histograms.
+    ReportHistogramActivity(*histogram, HISTOGRAM_CREATED);
+  } else {
+    // Update report on lookup histograms.
+    ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP);
+  }
+
+  DCHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_;
+  if (bucket_count_ != 0 &&
+      !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 nullptr;
+  }
+  return histogram;
+}
+
+HistogramBase* Histogram::FactoryGet(const std::string& name,
+                                     Sample minimum,
+                                     Sample maximum,
+                                     uint32_t bucket_count,
+                                     int32_t flags) {
+  bool valid_arguments =
+      InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  return Factory(name, minimum, maximum, bucket_count, flags).Build();
+}
+
+HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
+                                         TimeDelta minimum,
+                                         TimeDelta maximum,
+                                         uint32_t bucket_count,
+                                         int32_t flags) {
+  return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
+                    static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
+                    flags);
+}
+
+HistogramBase* Histogram::FactoryGet(const char* name,
+                                     Sample minimum,
+                                     Sample maximum,
+                                     uint32_t bucket_count,
+                                     int32_t flags) {
+  return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* Histogram::FactoryTimeGet(const char* name,
+                                         TimeDelta minimum,
+                                         TimeDelta maximum,
+                                         uint32_t bucket_count,
+                                         int32_t flags) {
+  return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
+                        flags);
+}
+
+std::unique_ptr<HistogramBase> Histogram::PersistentCreate(
+    const std::string& name,
+    Sample minimum,
+    Sample maximum,
+    const BucketRanges* ranges,
+    HistogramBase::AtomicCount* counts,
+    HistogramBase::AtomicCount* logged_counts,
+    uint32_t counts_size,
+    HistogramSamples::Metadata* meta,
+    HistogramSamples::Metadata* logged_meta) {
+  return WrapUnique(new Histogram(name, minimum, maximum, ranges, counts,
+                                  logged_counts, counts_size, meta,
+                                  logged_meta));
+}
+
+// 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;
+
+uint32_t Histogram::FindCorruption(const HistogramSamples& samples) const {
+  int inconsistencies = NO_INCONSISTENCIES;
+  Sample previous_range = -1;  // Bottom range is always 0.
+  for (uint32_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_t 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(uint32_t i) const {
+  return bucket_ranges_->range(i);
+}
+
+uint32_t Histogram::bucket_count() const {
+  return static_cast<uint32_t>(bucket_ranges_->bucket_count());
+}
+
+// static
+bool Histogram::InspectConstructionArguments(const std::string& name,
+                                             Sample* minimum,
+                                             Sample* maximum,
+                                             uint32_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<uint32_t>(*maximum - *minimum + 2))
+    return false;
+  return true;
+}
+
+uint64_t Histogram::name_hash() const {
+  return samples_->id();
+}
+
+HistogramType Histogram::GetHistogramType() const {
+  return HISTOGRAM;
+}
+
+bool Histogram::HasConstructionArguments(Sample expected_minimum,
+                                         Sample expected_maximum,
+                                         uint32_t expected_bucket_count) const {
+  return ((expected_minimum == declared_min_) &&
+          (expected_maximum == declared_max_) &&
+          (expected_bucket_count == bucket_count()));
+}
+
+void Histogram::Add(int value) {
+  AddCount(value, 1);
+}
+
+void Histogram::AddCount(int value, int count) {
+  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;
+  if (count <= 0) {
+    NOTREACHED();
+    return;
+  }
+  samples_->Accumulate(value, count);
+
+  FindAndRunCallback(value);
+}
+
+std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
+  return SnapshotSampleVector();
+}
+
+std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() {
+  DCHECK(!final_delta_created_);
+
+  std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector();
+  if (!logged_samples_) {
+    // If nothing has been previously logged, save this one as
+    // |logged_samples_| and gather another snapshot to return.
+    logged_samples_.swap(snapshot);
+    return SnapshotSampleVector();
+  }
+
+  // Subtract what was previously logged and update that information.
+  snapshot->Subtract(*logged_samples_);
+  logged_samples_->Add(*snapshot);
+  return snapshot;
+}
+
+std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
+  DCHECK(!final_delta_created_);
+  final_delta_created_ = true;
+
+  std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector();
+
+  // Subtract what was previously logged and then return.
+  if (logged_samples_)
+    snapshot->Subtract(*logged_samples_);
+  return snapshot;
+}
+
+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->WriteUInt32(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(HashMetricName(name), ranges));
+}
+
+Histogram::Histogram(const std::string& name,
+                     Sample minimum,
+                     Sample maximum,
+                     const BucketRanges* ranges,
+                     HistogramBase::AtomicCount* counts,
+                     HistogramBase::AtomicCount* logged_counts,
+                     uint32_t counts_size,
+                     HistogramSamples::Metadata* meta,
+                     HistogramSamples::Metadata* logged_meta)
+  : HistogramBase(name),
+    bucket_ranges_(ranges),
+    declared_min_(minimum),
+    declared_max_(maximum) {
+  if (ranges) {
+    samples_.reset(new SampleVector(HashMetricName(name),
+                                    counts, counts_size, meta, ranges));
+    logged_samples_.reset(new SampleVector(samples_->id(), logged_counts,
+                                           counts_size, logged_meta, ranges));
+  }
+}
+
+Histogram::~Histogram() {
+}
+
+bool Histogram::PrintEmptyBucket(uint32_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, uint32_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(uint32_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;
+  uint32_t bucket_count;
+  uint32_t 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;
+}
+
+std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
+  std::unique_ptr<SampleVector> samples(
+      new SampleVector(samples_->id(), bucket_ranges()));
+  samples->Add(*samples_);
+  return samples;
+}
+
+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.
+  std::unique_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.
+  uint32_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 (uint32_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_t remaining = sample_count;
+  int64_t past = 0;
+  // Output the actual histogram graph.
+  for (uint32_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 (uint32_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_t past,
+                                        const Count current,
+                                        const int64_t remaining,
+                                        const uint32_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_t* sum,
+                                      ListValue* buckets) const {
+  std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector();
+  *count = snapshot->TotalCount();
+  *sum = snapshot->sum();
+  uint32_t index = 0;
+  for (uint32_t i = 0; i < bucket_count(); ++i) {
+    Sample count_at_index = snapshot->GetCountAtIndex(i);
+    if (count_at_index > 0) {
+      std::unique_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.
+//------------------------------------------------------------------------------
+
+class LinearHistogram::Factory : public Histogram::Factory {
+ public:
+  Factory(const std::string& name,
+          HistogramBase::Sample minimum,
+          HistogramBase::Sample maximum,
+          uint32_t bucket_count,
+          int32_t flags,
+          const DescriptionPair* descriptions)
+    : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum,
+                         bucket_count, flags) {
+    descriptions_ = descriptions;
+  }
+  ~Factory() override = default;
+
+ protected:
+  BucketRanges* CreateRanges() override {
+    BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
+    LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
+    return ranges;
+  }
+
+  std::unique_ptr<HistogramBase> HeapAlloc(
+      const BucketRanges* ranges) override {
+    return WrapUnique(
+        new LinearHistogram(name_, minimum_, maximum_, ranges));
+  }
+
+  void FillHistogram(HistogramBase* base_histogram) override {
+    Histogram::Factory::FillHistogram(base_histogram);
+    LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
+    // Set range descriptions.
+    if (descriptions_) {
+      for (int i = 0; descriptions_[i].description; ++i) {
+        histogram->bucket_description_[descriptions_[i].sample] =
+            descriptions_[i].description;
+      }
+    }
+  }
+
+ private:
+  const DescriptionPair* descriptions_;
+
+  DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
+LinearHistogram::~LinearHistogram() {}
+
+HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
+                                           Sample minimum,
+                                           Sample maximum,
+                                           uint32_t bucket_count,
+                                           int32_t flags) {
+  return FactoryGetWithRangeDescription(
+      name, minimum, maximum, bucket_count, flags, NULL);
+}
+
+HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
+                                               TimeDelta minimum,
+                                               TimeDelta maximum,
+                                               uint32_t bucket_count,
+                                               int32_t flags) {
+  return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
+                    static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
+                    flags);
+}
+
+HistogramBase* LinearHistogram::FactoryGet(const char* name,
+                                           Sample minimum,
+                                           Sample maximum,
+                                           uint32_t bucket_count,
+                                           int32_t flags) {
+  return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
+}
+
+HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
+                                               TimeDelta minimum,
+                                               TimeDelta maximum,
+                                               uint32_t bucket_count,
+                                               int32_t flags) {
+  return FactoryTimeGet(std::string(name),  minimum, maximum, bucket_count,
+                        flags);
+}
+
+std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
+    const std::string& name,
+    Sample minimum,
+    Sample maximum,
+    const BucketRanges* ranges,
+    HistogramBase::AtomicCount* counts,
+    HistogramBase::AtomicCount* logged_counts,
+    uint32_t counts_size,
+    HistogramSamples::Metadata* meta,
+    HistogramSamples::Metadata* logged_meta) {
+  return WrapUnique(new LinearHistogram(name, minimum, maximum, ranges,
+                                              counts, logged_counts,
+                                              counts_size, meta, logged_meta));
+}
+
+HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
+    const std::string& name,
+    Sample minimum,
+    Sample maximum,
+    uint32_t bucket_count,
+    int32_t flags,
+    const DescriptionPair descriptions[]) {
+  bool valid_arguments = Histogram::InspectConstructionArguments(
+      name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
+      .Build();
+}
+
+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) {
+}
+
+LinearHistogram::LinearHistogram(const std::string& name,
+                                 Sample minimum,
+                                 Sample maximum,
+                                 const BucketRanges* ranges,
+                                 HistogramBase::AtomicCount* counts,
+                                 HistogramBase::AtomicCount* logged_counts,
+                                 uint32_t counts_size,
+                                 HistogramSamples::Metadata* meta,
+                                 HistogramSamples::Metadata* logged_meta)
+    : Histogram(name, minimum, maximum, ranges, counts, logged_counts,
+                counts_size, meta, logged_meta) {}
+
+double LinearHistogram::GetBucketSize(Count current, uint32_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(uint32_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(uint32_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));
+    // TODO(bcwhite): Remove once crbug/586622 is fixed.
+    base::debug::Alias(&linear_range);
+  }
+  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;
+  uint32_t bucket_count;
+  uint32_t 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.
+//------------------------------------------------------------------------------
+
+class BooleanHistogram::Factory : public Histogram::Factory {
+ public:
+  Factory(const std::string& name, int32_t flags)
+    : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
+  ~Factory() override = default;
+
+ protected:
+  BucketRanges* CreateRanges() override {
+    BucketRanges* ranges = new BucketRanges(3 + 1);
+    LinearHistogram::InitializeBucketRanges(1, 2, ranges);
+    return ranges;
+  }
+
+  std::unique_ptr<HistogramBase> HeapAlloc(
+      const BucketRanges* ranges) override {
+    return WrapUnique(new BooleanHistogram(name_, ranges));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
+HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
+                                            int32_t flags) {
+  return Factory(name, flags).Build();
+}
+
+HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
+  return FactoryGet(std::string(name), flags);
+}
+
+std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
+    const std::string& name,
+    const BucketRanges* ranges,
+    HistogramBase::AtomicCount* counts,
+    HistogramBase::AtomicCount* logged_counts,
+    HistogramSamples::Metadata* meta,
+    HistogramSamples::Metadata* logged_meta) {
+  return WrapUnique(new BooleanHistogram(
+      name, ranges, counts, logged_counts, meta, logged_meta));
+}
+
+HistogramType BooleanHistogram::GetHistogramType() const {
+  return BOOLEAN_HISTOGRAM;
+}
+
+BooleanHistogram::BooleanHistogram(const std::string& name,
+                                   const BucketRanges* ranges)
+    : LinearHistogram(name, 1, 2, ranges) {}
+
+BooleanHistogram::BooleanHistogram(const std::string& name,
+                                   const BucketRanges* ranges,
+                                   HistogramBase::AtomicCount* counts,
+                                   HistogramBase::AtomicCount* logged_counts,
+                                   HistogramSamples::Metadata* meta,
+                                   HistogramSamples::Metadata* logged_meta)
+    : LinearHistogram(name, 1, 2, ranges, counts, logged_counts, 2, meta,
+                      logged_meta) {}
+
+HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  std::string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  uint32_t bucket_count;
+  uint32_t 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:
+//------------------------------------------------------------------------------
+
+class CustomHistogram::Factory : public Histogram::Factory {
+ public:
+  Factory(const std::string& name,
+          const std::vector<Sample>* custom_ranges,
+          int32_t flags)
+    : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
+    custom_ranges_ = custom_ranges;
+  }
+  ~Factory() override = default;
+
+ protected:
+  BucketRanges* CreateRanges() override {
+    // 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 (uint32_t i = 0; i < ranges.size(); i++) {
+      bucket_ranges->set_range(i, ranges[i]);
+    }
+    bucket_ranges->ResetChecksum();
+    return bucket_ranges;
+  }
+
+  std::unique_ptr<HistogramBase> HeapAlloc(
+      const BucketRanges* ranges) override {
+    return WrapUnique(new CustomHistogram(name_, ranges));
+  }
+
+ private:
+  const std::vector<Sample>* custom_ranges_;
+
+  DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
+HistogramBase* CustomHistogram::FactoryGet(
+    const std::string& name,
+    const std::vector<Sample>& custom_ranges,
+    int32_t flags) {
+  CHECK(ValidateCustomRanges(custom_ranges));
+
+  return Factory(name, &custom_ranges, flags).Build();
+}
+
+HistogramBase* CustomHistogram::FactoryGet(
+    const char* name,
+    const std::vector<Sample>& custom_ranges,
+    int32_t flags) {
+  return FactoryGet(std::string(name), custom_ranges, flags);
+}
+
+std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
+    const std::string& name,
+    const BucketRanges* ranges,
+    HistogramBase::AtomicCount* counts,
+    HistogramBase::AtomicCount* logged_counts,
+    uint32_t counts_size,
+    HistogramSamples::Metadata* meta,
+    HistogramSamples::Metadata* logged_meta) {
+  return WrapUnique(new CustomHistogram(
+      name, ranges, counts, logged_counts, counts_size, meta, logged_meta));
+}
+
+HistogramType CustomHistogram::GetHistogramType() const {
+  return CUSTOM_HISTOGRAM;
+}
+
+// static
+std::vector<Sample> CustomHistogram::ArrayToCustomRanges(
+    const Sample* values, uint32_t num_values) {
+  std::vector<Sample> all_values;
+  for (uint32_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) {}
+
+CustomHistogram::CustomHistogram(const std::string& name,
+                                 const BucketRanges* ranges,
+                                 HistogramBase::AtomicCount* counts,
+                                 HistogramBase::AtomicCount* logged_counts,
+                                 uint32_t counts_size,
+                                 HistogramSamples::Metadata* meta,
+                                 HistogramSamples::Metadata* logged_meta)
+    : Histogram(name,
+                ranges->range(1),
+                ranges->range(ranges->bucket_count() - 1),
+                ranges,
+                counts,
+                logged_counts,
+                counts_size,
+                meta,
+                logged_meta) {}
+
+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 (uint32_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*/, uint32_t /*i*/) const {
+  return 1;
+}
+
+// static
+HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  std::string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  uint32_t bucket_count;
+  uint32_t 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 (uint32_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 (uint32_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;
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/histogram.h b/libchrome/base/metrics/histogram.h
new file mode 100644
index 0000000..2283a4d
--- /dev/null
+++ b/libchrome/base/metrics/histogram.h
@@ -0,0 +1,552 @@
+// Copyright (c) 2012 The Chromium 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 <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/macros.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 PersistentMemoryAllocator;
+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 uint32_t kBucketCount_MAX;
+
+  typedef std::vector<Count> Counts;
+
+  ~Histogram() override;
+
+  //----------------------------------------------------------------------------
+  // 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,
+                                   uint32_t bucket_count,
+                                   int32_t flags);
+  static HistogramBase* FactoryTimeGet(const std::string& name,
+                                       base::TimeDelta minimum,
+                                       base::TimeDelta maximum,
+                                       uint32_t bucket_count,
+                                       int32_t flags);
+
+  // Overloads of the above two functions that take a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   uint32_t bucket_count,
+                                   int32_t flags);
+  static HistogramBase* FactoryTimeGet(const char* name,
+                                       base::TimeDelta minimum,
+                                       base::TimeDelta maximum,
+                                       uint32_t bucket_count,
+                                       int32_t flags);
+
+  // Create a histogram using data in persistent storage.
+  static std::unique_ptr<HistogramBase> PersistentCreate(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      const BucketRanges* ranges,
+      HistogramBase::AtomicCount* counts,
+      HistogramBase::AtomicCount* logged_counts,
+      uint32_t counts_size,
+      HistogramSamples::Metadata* meta,
+      HistogramSamples::Metadata* logged_meta);
+
+  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). Flag definitions are located
+  // under "enum Inconsistency" in base/metrics/histogram_base.h.
+  uint32_t 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(uint32_t i) const;
+  virtual uint32_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,
+                                           uint32_t* bucket_count);
+
+  // HistogramBase implementation:
+  uint64_t name_hash() const override;
+  HistogramType GetHistogramType() const override;
+  bool HasConstructionArguments(Sample expected_minimum,
+                                Sample expected_maximum,
+                                uint32_t expected_bucket_count) const override;
+  void Add(Sample value) override;
+  void AddCount(Sample value, int count) override;
+  std::unique_ptr<HistogramSamples> SnapshotSamples() const override;
+  std::unique_ptr<HistogramSamples> SnapshotDelta() override;
+  std::unique_ptr<HistogramSamples> SnapshotFinalDelta() 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:
+  // This class, defined entirely within the .cc file, contains all the
+  // common logic for building a Histogram and can be overridden by more
+  // specific types to alter details of how the creation is done. It is
+  // defined as an embedded class (rather than an anonymous one) so it
+  // can access the protected constructors.
+  class Factory;
+
+  // |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);
+
+  // Traditionally, histograms allocate their own memory for the bucket
+  // vector but "shared" histograms use memory regions allocated from a
+  // special memory segment that is passed in here.  It is assumed that
+  // the life of this memory is managed externally and exceeds the lifetime
+  // of this object. Practically, this memory is never released until the
+  // process exits and the OS cleans it up.
+  Histogram(const std::string& name,
+            Sample minimum,
+            Sample maximum,
+            const BucketRanges* ranges,
+            HistogramBase::AtomicCount* counts,
+            HistogramBase::AtomicCount* logged_counts,
+            uint32_t counts_size,
+            HistogramSamples::Metadata* meta,
+            HistogramSamples::Metadata* logged_meta);
+
+  // 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(uint32_t index) const;
+
+  // Get normalized size, relative to the ranges(i).
+  virtual double GetBucketSize(Count current, uint32_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(uint32_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, CorruptSampleCounts);
+
+  friend class StatisticsRecorder;  // To allow it to delete duplicates.
+  friend class StatisticsRecorderTest;
+
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  // Implementation of SnapshotSamples function.
+  std::unique_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_t past,
+                               const Count current,
+                               const int64_t remaining,
+                               const uint32_t i,
+                               std::string* output) const;
+
+  // WriteJSON calls these.
+  void GetParameters(DictionaryValue* params) const override;
+
+  void GetCountAndBucketData(Count* count,
+                             int64_t* 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.
+  std::unique_ptr<SampleVector> samples_;
+
+  // Also keep a previous uploaded state for calculating deltas.
+  std::unique_ptr<HistogramSamples> logged_samples_;
+
+  // Flag to indicate if PrepareFinalDelta has been previously called. It is
+  // used to DCHECK that a final delta is not created multiple times.
+  mutable bool final_delta_created_ = false;
+
+  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,
+                                   uint32_t bucket_count,
+                                   int32_t flags);
+  static HistogramBase* FactoryTimeGet(const std::string& name,
+                                       TimeDelta minimum,
+                                       TimeDelta maximum,
+                                       uint32_t bucket_count,
+                                       int32_t flags);
+
+  // Overloads of the above two functions that take a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   uint32_t bucket_count,
+                                   int32_t flags);
+  static HistogramBase* FactoryTimeGet(const char* name,
+                                       TimeDelta minimum,
+                                       TimeDelta maximum,
+                                       uint32_t bucket_count,
+                                       int32_t flags);
+
+  // Create a histogram using data in persistent storage.
+  static std::unique_ptr<HistogramBase> PersistentCreate(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      const BucketRanges* ranges,
+      HistogramBase::AtomicCount* counts,
+      HistogramBase::AtomicCount* logged_counts,
+      uint32_t counts_size,
+      HistogramSamples::Metadata* meta,
+      HistogramSamples::Metadata* logged_meta);
+
+  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,
+      uint32_t bucket_count,
+      int32_t flags,
+      const DescriptionPair descriptions[]);
+
+  static void InitializeBucketRanges(Sample minimum,
+                                     Sample maximum,
+                                     BucketRanges* ranges);
+
+  // Overridden from Histogram:
+  HistogramType GetHistogramType() const override;
+
+ protected:
+  class Factory;
+
+  LinearHistogram(const std::string& name,
+                  Sample minimum,
+                  Sample maximum,
+                  const BucketRanges* ranges);
+
+  LinearHistogram(const std::string& name,
+                  Sample minimum,
+                  Sample maximum,
+                  const BucketRanges* ranges,
+                  HistogramBase::AtomicCount* counts,
+                  HistogramBase::AtomicCount* logged_counts,
+                  uint32_t counts_size,
+                  HistogramSamples::Metadata* meta,
+                  HistogramSamples::Metadata* logged_meta);
+
+  double GetBucketSize(Count current, uint32_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(uint32_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(uint32_t index) const override;
+
+ private:
+  friend BASE_EXPORT 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_t flags);
+
+  // Overload of the above function that takes a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name, int32_t flags);
+
+  // Create a histogram using data in persistent storage.
+  static std::unique_ptr<HistogramBase> PersistentCreate(
+      const std::string& name,
+      const BucketRanges* ranges,
+      HistogramBase::AtomicCount* counts,
+      HistogramBase::AtomicCount* logged_counts,
+      HistogramSamples::Metadata* meta,
+      HistogramSamples::Metadata* logged_meta);
+
+  HistogramType GetHistogramType() const override;
+
+ protected:
+  class Factory;
+
+ private:
+  BooleanHistogram(const std::string& name, const BucketRanges* ranges);
+  BooleanHistogram(const std::string& name,
+                   const BucketRanges* ranges,
+                   HistogramBase::AtomicCount* counts,
+                   HistogramBase::AtomicCount* logged_counts,
+                   HistogramSamples::Metadata* meta,
+                   HistogramSamples::Metadata* logged_meta);
+
+  friend BASE_EXPORT 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_t flags);
+
+  // Overload of the above function that takes a const char* |name| param,
+  // to avoid code bloat from the std::string constructor being inlined into
+  // call sites.
+  static HistogramBase* FactoryGet(const char* name,
+                                   const std::vector<Sample>& custom_ranges,
+                                   int32_t flags);
+
+  // Create a histogram using data in persistent storage.
+  static std::unique_ptr<HistogramBase> PersistentCreate(
+      const std::string& name,
+      const BucketRanges* ranges,
+      HistogramBase::AtomicCount* counts,
+      HistogramBase::AtomicCount* logged_counts,
+      uint32_t counts_size,
+      HistogramSamples::Metadata* meta,
+      HistogramSamples::Metadata* logged_meta);
+
+  // 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,
+                                                 uint32_t num_values);
+ protected:
+  class Factory;
+
+  CustomHistogram(const std::string& name,
+                  const BucketRanges* ranges);
+
+  CustomHistogram(const std::string& name,
+                  const BucketRanges* ranges,
+                  HistogramBase::AtomicCount* counts,
+                  HistogramBase::AtomicCount* logged_counts,
+                  uint32_t counts_size,
+                  HistogramSamples::Metadata* meta,
+                  HistogramSamples::Metadata* logged_meta);
+
+  // HistogramBase implementation:
+  bool SerializeInfoImpl(base::Pickle* pickle) const override;
+
+  double GetBucketSize(Count current, uint32_t i) const override;
+
+ private:
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
+
+  DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_H_
diff --git a/libchrome/base/metrics/histogram_base.cc b/libchrome/base/metrics/histogram_base.cc
new file mode 100644
index 0000000..8c4f1ec
--- /dev/null
+++ b/libchrome/base/metrics/histogram_base.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.
+
+#include "base/metrics/histogram_base.h"
+
+#include <limits.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.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";
+  }
+  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::report_histogram_ = nullptr;
+
+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_t flags) {
+  HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+  subtle::NoBarrier_Store(&flags_, old_flags | flags);
+}
+
+void HistogramBase::ClearFlags(int32_t flags) {
+  HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+  subtle::NoBarrier_Store(&flags_, old_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);
+}
+
+uint32_t HistogramBase::FindCorruption(
+    const HistogramSamples& /*samples*/) const {
+  // Not supported by default.
+  return NO_INCONSISTENCIES;
+}
+
+void HistogramBase::WriteJSON(std::string* output) const {
+  Count count;
+  int64_t sum;
+  std::unique_ptr<ListValue> buckets(new ListValue());
+  GetCountAndBucketData(&count, &sum, buckets.get());
+  std::unique_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", std::move(parameters));
+  root.Set("buckets", std::move(buckets));
+  root.SetInteger("pid", GetCurrentProcId());
+  serializer.Serialize(root);
+}
+
+// static
+void HistogramBase::EnableActivityReportHistogram(
+    const std::string& process_type) {
+  DCHECK(!report_histogram_);
+  size_t existing = StatisticsRecorder::GetHistogramCount();
+  if (existing != 0) {
+    DVLOG(1) << existing
+             << " histograms were created before reporting was enabled.";
+  }
+
+  std::string name =
+      "UMA.Histograms.Activity" +
+      (process_type.empty() ? process_type : "." + process_type);
+
+  // Calling FactoryGet() here rather than using a histogram-macro works
+  // around some problems with tests that could end up seeing the results
+  // histogram when not expected due to a bad interaction between
+  // HistogramTester and StatisticsRecorder.
+  report_histogram_ = LinearHistogram::FactoryGet(
+      name, 1, HISTOGRAM_REPORT_MAX, HISTOGRAM_REPORT_MAX + 1,
+      kUmaTargetedHistogramFlag);
+  report_histogram_->Add(HISTOGRAM_REPORT_CREATED);
+}
+
+void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const {
+  if ((flags() & kCallbackExists) == 0)
+    return;
+
+  StatisticsRecorder::OnSampleCallback cb =
+      StatisticsRecorder::FindCallback(histogram_name());
+  if (!cb.is_null())
+    cb.Run(sample);
+}
+
+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);
+}
+
+// static
+void HistogramBase::ReportHistogramActivity(const HistogramBase& histogram,
+                                            ReportActivity activity) {
+  if (!report_histogram_)
+    return;
+
+  const int32_t flags = histogram.flags_;
+  HistogramReport report_type = HISTOGRAM_REPORT_MAX;
+  switch (activity) {
+    case HISTOGRAM_CREATED:
+      report_histogram_->Add(HISTOGRAM_REPORT_HISTOGRAM_CREATED);
+      switch (histogram.GetHistogramType()) {
+        case HISTOGRAM:
+          report_type = HISTOGRAM_REPORT_TYPE_LOGARITHMIC;
+          break;
+        case LINEAR_HISTOGRAM:
+          report_type = HISTOGRAM_REPORT_TYPE_LINEAR;
+          break;
+        case BOOLEAN_HISTOGRAM:
+          report_type = HISTOGRAM_REPORT_TYPE_BOOLEAN;
+          break;
+        case CUSTOM_HISTOGRAM:
+          report_type = HISTOGRAM_REPORT_TYPE_CUSTOM;
+          break;
+        case SPARSE_HISTOGRAM:
+          report_type = HISTOGRAM_REPORT_TYPE_SPARSE;
+          break;
+      }
+      report_histogram_->Add(report_type);
+      if (flags & kIsPersistent)
+        report_histogram_->Add(HISTOGRAM_REPORT_FLAG_PERSISTENT);
+      if ((flags & kUmaStabilityHistogramFlag) == kUmaStabilityHistogramFlag)
+        report_histogram_->Add(HISTOGRAM_REPORT_FLAG_UMA_STABILITY);
+      else if (flags & kUmaTargetedHistogramFlag)
+        report_histogram_->Add(HISTOGRAM_REPORT_FLAG_UMA_TARGETED);
+      break;
+
+    case HISTOGRAM_LOOKUP:
+      report_histogram_->Add(HISTOGRAM_REPORT_HISTOGRAM_LOOKUP);
+      break;
+  }
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/histogram_base.h b/libchrome/base/metrics/histogram_base.h
new file mode 100644
index 0000000..d240099
--- /dev/null
+++ b/libchrome/base/metrics/histogram_base.h
@@ -0,0 +1,279 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BucketRanges;
+class DictionaryValue;
+class HistogramBase;
+class HistogramSamples;
+class ListValue;
+class Pickle;
+class PickleIterator;
+
+////////////////////////////////////////////////////////////////////////////////
+// This enum is 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 HistogramType {
+  HISTOGRAM,
+  LINEAR_HISTOGRAM,
+  BOOLEAN_HISTOGRAM,
+  CUSTOM_HISTOGRAM,
+  SPARSE_HISTOGRAM,
+};
+
+std::string HistogramTypeToString(HistogramType type);
+
+// This enum is used for reporting how many histograms and of what types and
+// variations are being created. It has to be in the main .h file so it is
+// visible to files that define the various histogram types.
+enum HistogramReport {
+  // Count the number of reports created. The other counts divided by this
+  // number will give the average per run of the program.
+  HISTOGRAM_REPORT_CREATED = 0,
+
+  // Count the total number of histograms created. It is the limit against
+  // which all others are compared.
+  HISTOGRAM_REPORT_HISTOGRAM_CREATED = 1,
+
+  // Count the total number of histograms looked-up. It's better to cache
+  // the result of a single lookup rather than do it repeatedly.
+  HISTOGRAM_REPORT_HISTOGRAM_LOOKUP = 2,
+
+  // These count the individual histogram types. This must follow the order
+  // of HistogramType above.
+  HISTOGRAM_REPORT_TYPE_LOGARITHMIC = 3,
+  HISTOGRAM_REPORT_TYPE_LINEAR = 4,
+  HISTOGRAM_REPORT_TYPE_BOOLEAN = 5,
+  HISTOGRAM_REPORT_TYPE_CUSTOM = 6,
+  HISTOGRAM_REPORT_TYPE_SPARSE = 7,
+
+  // These indicate the individual flags that were set.
+  HISTOGRAM_REPORT_FLAG_UMA_TARGETED = 8,
+  HISTOGRAM_REPORT_FLAG_UMA_STABILITY = 9,
+  HISTOGRAM_REPORT_FLAG_PERSISTENT = 10,
+
+  // This must be last.
+  HISTOGRAM_REPORT_MAX = 11
+};
+
+// Create or find existing histogram that matches the pickled info.
+// Returns NULL if the pickled data has problems.
+BASE_EXPORT 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,
+
+    // Indicates that a callback exists for when a new sample is recorded on
+    // this histogram. We store this as a flag with the histogram since
+    // histograms can be in performance critical code, and this allows us
+    // to shortcut looking up the callback if it doesn't exist.
+    kCallbackExists = 0x20,
+
+    // Indicates that the histogram is held in "persistent" memory and may
+    // be accessible between processes. This is only possible if such a
+    // memory segment has been created/attached, used to create a Persistent-
+    // MemoryAllocator, and that loaded into the Histogram module before this
+    // histogram is created.
+    kIsPersistent = 0x40,
+
+    // Only for Histogram and its sub classes: fancy bucket-naming support.
+    kHexRangePrintingFlag = 0x8000,
+  };
+
+  // Histogram data inconsistency types.
+  enum Inconsistency : uint32_t {
+    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();
+
+  const 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;
+
+  // Get a unique ID for this histogram's samples.
+  virtual uint64_t name_hash() const = 0;
+
+  // Operations with Flags enum.
+  int32_t flags() const { return subtle::NoBarrier_Load(&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,
+      uint32_t expected_bucket_count) const = 0;
+
+  virtual void Add(Sample value) = 0;
+
+  // In Add function the |value| bucket is increased by one, but in some use
+  // cases we need to increase this value by an arbitrary integer. AddCount
+  // function increases the |value| bucket by |count|. |count| should be greater
+  // than or equal to 1.
+  virtual void AddCount(Sample value, int count) = 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 uint32_t FindCorruption(const HistogramSamples& samples) const;
+
+  // Snapshot the current complete set of sample data.
+  // Override with atomic/locked snapshot if needed.
+  virtual std::unique_ptr<HistogramSamples> SnapshotSamples() const = 0;
+
+  // Calculate the change (delta) in histogram counts since the previous call
+  // to this method. Each successive call will return only those counts
+  // changed since the last call.
+  virtual std::unique_ptr<HistogramSamples> SnapshotDelta() = 0;
+
+  // Calculate the change (delta) in histogram counts since the previous call
+  // to SnapshotDelta() but do so without modifying any internal data as to
+  // what was previous logged. After such a call, no further calls to this
+  // method or to SnapshotDelta() should be done as the result would include
+  // data previously returned. Because no internal data is changed, this call
+  // can be made on "const" histograms such as those with data held in
+  // read-only memory.
+  virtual std::unique_ptr<HistogramSamples> SnapshotFinalDelta() 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;
+
+  // This enables a histogram that reports the what types of histograms are
+  // created and their flags. It must be called while still single-threaded.
+  //
+  // IMPORTANT: Callers must update tools/metrics/histograms/histograms.xml
+  // with the following histogram:
+  //    UMA.Histograms.process_type.Creations
+  static void EnableActivityReportHistogram(const std::string& process_type);
+
+ protected:
+  enum ReportActivity { HISTOGRAM_CREATED, HISTOGRAM_LOOKUP };
+
+  // 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_t* 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;
+
+  // Retrieves the callback for this histogram, if one exists, and runs it
+  // passing |sample| as the parameter.
+  void FindAndRunCallback(Sample sample) const;
+
+  // Update report with an |activity| that occurred for |histogram|.
+  static void ReportHistogramActivity(const HistogramBase& histogram,
+                                      ReportActivity activicty);
+
+  // Retrieves the global histogram reporting what histograms are created.
+  static HistogramBase* report_histogram_;
+
+ private:
+  friend class HistogramBaseTest;
+
+  const std::string histogram_name_;
+  AtomicCount flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramBase);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_BASE_H_
diff --git a/libchrome/base/metrics/histogram_base_unittest.cc b/libchrome/base/metrics/histogram_base_unittest.cc
new file mode 100644
index 0000000..1eb8fd4
--- /dev/null
+++ b/libchrome/base/metrics/histogram_base_unittest.cc
@@ -0,0 +1,222 @@
+// Copyright (c) 2012 The Chromium Authors. 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).
+    ResetStatisticsRecorder();
+  }
+
+  ~HistogramBaseTest() override {
+    HistogramBase::report_histogram_ = nullptr;
+  }
+
+  void ResetStatisticsRecorder() {
+    // It is necessary to fully destruct any existing StatisticsRecorder
+    // before creating a new one.
+    statistics_recorder_.reset();
+    statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
+  }
+
+  HistogramBase* GetCreationReportHistogram(const std::string& name) {
+    HistogramBase::EnableActivityReportHistogram(name);
+    return HistogramBase::report_histogram_;
+  }
+
+ private:
+  std::unique_ptr<StatisticsRecorder> statistics_recorder_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramBaseTest);
+};
+
+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());
+}
+
+TEST_F(HistogramBaseTest, CreationReportHistogram) {
+  // Enabled creation report. Itself is not included in the report.
+  HistogramBase* report = GetCreationReportHistogram("CreationReportTest");
+  ASSERT_TRUE(report);
+
+  std::vector<HistogramBase::Sample> ranges;
+  ranges.push_back(1);
+  ranges.push_back(2);
+  ranges.push_back(4);
+  ranges.push_back(8);
+  ranges.push_back(10);
+
+  // Create all histogram types and verify counts.
+  Histogram::FactoryGet("CRH-Histogram", 1, 10, 5, 0);
+  LinearHistogram::FactoryGet("CRH-Linear", 1, 10, 5, 0);
+  BooleanHistogram::FactoryGet("CRH-Boolean", 0);
+  CustomHistogram::FactoryGet("CRH-Custom", ranges, 0);
+  SparseHistogram::FactoryGet("CRH-Sparse", 0);
+
+  std::unique_ptr<HistogramSamples> samples = report->SnapshotSamples();
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_CREATED));
+  EXPECT_EQ(5, samples->GetCount(HISTOGRAM_REPORT_HISTOGRAM_CREATED));
+  EXPECT_EQ(0, samples->GetCount(HISTOGRAM_REPORT_HISTOGRAM_LOOKUP));
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_TYPE_LOGARITHMIC));
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_TYPE_LINEAR));
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_TYPE_BOOLEAN));
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_TYPE_CUSTOM));
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_TYPE_SPARSE));
+
+  // Create all flag types and verify counts.
+  Histogram::FactoryGet("CRH-Histogram-UMA-Targeted", 1, 10, 5,
+                        HistogramBase::kUmaTargetedHistogramFlag);
+  Histogram::FactoryGet("CRH-Histogram-UMA-Stability", 1, 10, 5,
+                        HistogramBase::kUmaStabilityHistogramFlag);
+  SparseHistogram::FactoryGet("CRH-Sparse-UMA-Targeted",
+                              HistogramBase::kUmaTargetedHistogramFlag);
+  SparseHistogram::FactoryGet("CRH-Sparse-UMA-Stability",
+                              HistogramBase::kUmaStabilityHistogramFlag);
+  samples = report->SnapshotSamples();
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_CREATED));
+  EXPECT_EQ(9, samples->GetCount(HISTOGRAM_REPORT_HISTOGRAM_CREATED));
+  EXPECT_EQ(0, samples->GetCount(HISTOGRAM_REPORT_HISTOGRAM_LOOKUP));
+  EXPECT_EQ(2, samples->GetCount(HISTOGRAM_REPORT_FLAG_UMA_TARGETED));
+  EXPECT_EQ(2, samples->GetCount(HISTOGRAM_REPORT_FLAG_UMA_STABILITY));
+
+  // Do lookup of existing histograms and verify counts.
+  Histogram::FactoryGet("CRH-Histogram", 1, 10, 5, 0);
+  LinearHistogram::FactoryGet("CRH-Linear", 1, 10, 5, 0);
+  BooleanHistogram::FactoryGet("CRH-Boolean", 0);
+  CustomHistogram::FactoryGet("CRH-Custom", ranges, 0);
+  SparseHistogram::FactoryGet("CRH-Sparse", 0);
+  samples = report->SnapshotSamples();
+  EXPECT_EQ(1, samples->GetCount(HISTOGRAM_REPORT_CREATED));
+  EXPECT_EQ(9, samples->GetCount(HISTOGRAM_REPORT_HISTOGRAM_CREATED));
+  EXPECT_EQ(5, samples->GetCount(HISTOGRAM_REPORT_HISTOGRAM_LOOKUP));
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/histogram_delta_serialization.cc b/libchrome/base/metrics/histogram_delta_serialization.cc
new file mode 100644
index 0000000..3e5d154
--- /dev/null
+++ b/libchrome/base/metrics/histogram_delta_serialization.cc
@@ -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.
+
+#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/metrics/statistics_recorder.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,
+    bool include_persistent) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  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(
+      StatisticsRecorder::begin(include_persistent), StatisticsRecorder::end(),
+      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(thread_checker_.CalledOnValidThread());
+  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) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  inconsistencies_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::UniqueInconsistencyDetected(
+    HistogramBase::Inconsistency problem) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  inconsistencies_unique_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::InconsistencyDetectedInLoggedCount(
+    int amount) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  inconsistent_snapshot_histogram_->Add(std::abs(amount));
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/histogram_delta_serialization.h b/libchrome/base/metrics/histogram_delta_serialization.h
new file mode 100644
index 0000000..3bb04cb
--- /dev/null
+++ b/libchrome/base/metrics/histogram_delta_serialization.h
@@ -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.
+
+#ifndef BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+#define BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+#include "base/threading/thread_checker.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. Setting |include_persistent|
+  // will include histograms held in persistent memory (and thus may be reported
+  // elsewhere); otherwise only histograms local to this process are serialized.
+  void PrepareAndSerializeDeltas(std::vector<std::string>* serialized_deltas,
+                                 bool include_persistent);
+
+  // 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;
+
+  ThreadChecker thread_checker_;
+
+  // 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/libchrome/base/metrics/histogram_delta_serialization_unittest.cc b/libchrome/base/metrics/histogram_delta_serialization_unittest.cc
new file mode 100644
index 0000000..719bc70
--- /dev/null
+++ b/libchrome/base/metrics/histogram_delta_serialization_unittest.cc
@@ -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.
+
+#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) {
+  std::unique_ptr<StatisticsRecorder> statistic_recorder(
+      StatisticsRecorder::CreateTemporaryForTesting());
+  HistogramDeltaSerialization serializer("HistogramDeltaSerializationTest");
+  std::vector<std::string> deltas;
+  // Nothing was changed yet.
+  serializer.PrepareAndSerializeDeltas(&deltas, true);
+  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, true);
+  EXPECT_FALSE(deltas.empty());
+
+  HistogramDeltaSerialization::DeserializeAndAddSamples(deltas);
+
+  // The histogram has kIPCSerializationSourceFlag. So samples will be ignored.
+  std::unique_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);
+
+  std::unique_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/libchrome/base/metrics/histogram_flattener.h b/libchrome/base/metrics/histogram_flattener.h
new file mode 100644
index 0000000..b5fe976
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/metrics/histogram_macros.h b/libchrome/base/metrics/histogram_macros.h
new file mode 100644
index 0000000..ce1811a
--- /dev/null
+++ b/libchrome/base/metrics/histogram_macros.h
@@ -0,0 +1,298 @@
+// 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/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+// Macros for efficient use of histograms. See documentation in histogram.h.
+//
+// UMA_HISTOGRAM_SPARSE_SLOWLY is defined in sparse_histogram.h as it has
+// different #include dependencies.
+
+//------------------------------------------------------------------------------
+// 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).
+
+// In some cases (integration into 3rd party code), it's useful to seperate the
+// definition of |atomic_histogram_poiner| from its use. To achieve this we
+// define HISTOGRAM_POINTER_USE, which uses an |atomic_histogram_pointer|, and
+// STATIC_HISTOGRAM_POINTER_BLOCK, which defines an |atomic_histogram_pointer|
+// and forwards to HISTOGRAM_POINTER_USE.
+#define HISTOGRAM_POINTER_USE(atomic_histogram_pointer,                   \
+                              constant_histogram_name,                    \
+                              histogram_add_method_invocation,            \
+                              histogram_factory_get_invocation)           \
+  do {                                                                    \
+    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)
+
+// Defines the static |atomic_histogram_pointer| and forwards to
+// HISTOGRAM_POINTER_USE.
+#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;             \
+    HISTOGRAM_POINTER_USE(&atomic_histogram_pointer, constant_histogram_name, \
+                          histogram_add_method_invocation,                    \
+                          histogram_factory_get_invocation);                  \
+  } while (0)
+
+//------------------------------------------------------------------------------
+// Provide easy general purpose histogram in a macro, just like stats counters.
+// Most of these macros use 50 buckets, but check the definition for details.
+//
+// All of these macros must be called with |name| as a runtime constant --- it
+// doesn't have to literally be a constant, but it must be the same string on
+// all calls from a particular call site. If this rule is violated,
+// STATIC_HISTOGRAM_POINTER_BLOCK will DCHECK, and if DCHECKS are disabled, the
+// data will be written to the wrong histogram.
+
+#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_1000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000, 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_MEMORY_LARGE_MB(name, sample) \
+    UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 64000, 100)
+
+#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/libchrome/base/metrics/histogram_macros_unittest.cc b/libchrome/base/metrics/histogram_macros_unittest.cc
new file mode 100644
index 0000000..c599161
--- /dev/null
+++ b/libchrome/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/libchrome/base/metrics/histogram_samples.cc b/libchrome/base/metrics/histogram_samples.cc
new file mode 100644
index 0000000..ea3b987
--- /dev/null
+++ b/libchrome/base/metrics/histogram_samples.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/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
+
+// Don't try to delegate behavior to the constructor below that accepts a
+// Matadata pointer by passing &local_meta_. Such cannot be reliably passed
+// because it has not yet been constructed -- no member variables have; the
+// class itself is in the middle of being constructed. Using it to
+// initialize meta_ is okay because the object now exists and local_meta_
+// is before meta_ in the construction order.
+HistogramSamples::HistogramSamples(uint64_t id)
+    : meta_(&local_meta_) {
+  meta_->id = id;
+}
+
+HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta)
+    : meta_(meta) {
+  DCHECK(meta_->id == 0 || meta_->id == id);
+
+  // It's possible that |meta| is contained in initialized, read-only memory
+  // so it's essential that no write be done in that case.
+  if (!meta_->id)
+    meta_->id = id;
+}
+
+HistogramSamples::~HistogramSamples() {}
+
+void HistogramSamples::Add(const HistogramSamples& other) {
+  IncreaseSum(other.sum());
+  subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
+                                    other.redundant_count());
+  bool success = AddSubtractImpl(other.Iterator().get(), ADD);
+  DCHECK(success);
+}
+
+bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
+  int64_t sum;
+  HistogramBase::Count redundant_count;
+
+  if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
+    return false;
+
+  IncreaseSum(sum);
+  subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
+                                    redundant_count);
+
+  SampleCountPickleIterator pickle_iter(iter);
+  return AddSubtractImpl(&pickle_iter, ADD);
+}
+
+void HistogramSamples::Subtract(const HistogramSamples& other) {
+  IncreaseSum(-other.sum());
+  subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count,
+                                    -other.redundant_count());
+  bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
+  DCHECK(success);
+}
+
+bool HistogramSamples::Serialize(Pickle* pickle) const {
+  if (!pickle->WriteInt64(sum()))
+    return false;
+  if (!pickle->WriteInt(redundant_count()))
+    return false;
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  for (std::unique_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_t diff) {
+#ifdef ARCH_CPU_64_BITS
+  subtle::NoBarrier_AtomicIncrement(&meta_->sum, diff);
+#else
+  meta_->sum += diff;
+#endif
+}
+
+void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
+  subtle::NoBarrier_AtomicIncrement(&meta_->redundant_count, diff);
+}
+
+SampleCountIterator::~SampleCountIterator() {}
+
+bool SampleCountIterator::GetBucketIndex(size_t* /*index*/) const {
+  DCHECK(!Done());
+  return false;
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/histogram_samples.h b/libchrome/base/metrics/histogram_samples.h
new file mode 100644
index 0000000..e28573f
--- /dev/null
+++ b/libchrome/base/metrics/histogram_samples.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class Pickle;
+class PickleIterator;
+class SampleCountIterator;
+
+// HistogramSamples is a container storing all samples of a histogram. All
+// elements must be of a fixed width to ensure 32/64-bit interoperability.
+// If this structure changes, bump the version number for kTypeIdHistogram
+// in persistent_histogram_allocator.cc.
+class BASE_EXPORT HistogramSamples {
+ public:
+  struct Metadata {
+    // Initialized when the sample-set is first created with a value provided
+    // by the caller. It is generally used to identify the sample-set across
+    // threads and processes, though not necessarily uniquely as it is possible
+    // to have multiple sample-sets representing subsets of the data.
+    uint64_t id;
+
+    // The sum of all the entries, effectivly the sum(sample * count) for
+    // all samples. Despite being atomic, no guarantees are made on the
+    // accuracy of this value; there may be races during histogram
+    // accumulation and snapshotting that we choose to accept. It should
+    // be treated as approximate.
+#ifdef ARCH_CPU_64_BITS
+    subtle::Atomic64 sum;
+#else
+    // 32-bit systems don't have atomic 64-bit operations. Use a basic type
+    // and don't worry about "shearing".
+    int64_t sum;
+#endif
+
+    // A "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;
+
+    Metadata() : id(0), sum(0), redundant_count(0) {}
+  };
+
+  explicit HistogramSamples(uint64_t id);
+  HistogramSamples(uint64_t id, Metadata* meta);
+  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 std::unique_ptr<SampleCountIterator> Iterator() const = 0;
+  virtual bool Serialize(Pickle* pickle) const;
+
+  // Accessor fuctions.
+  uint64_t id() const { return meta_->id; }
+  int64_t sum() const {
+#ifdef ARCH_CPU_64_BITS
+    return subtle::NoBarrier_Load(&meta_->sum);
+#else
+    return meta_->sum;
+#endif
+  }
+  HistogramBase::Count redundant_count() const {
+    return subtle::NoBarrier_Load(&meta_->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_t diff);
+  void IncreaseRedundantCount(HistogramBase::Count diff);
+
+ private:
+  // In order to support histograms shared through an external memory segment,
+  // meta values may be the local storage or external storage depending on the
+  // wishes of the derived class.
+  Metadata local_meta_;
+  Metadata* meta_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
+};
+
+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/libchrome/base/metrics/histogram_snapshot_manager.cc b/libchrome/base/metrics/histogram_snapshot_manager.cc
new file mode 100644
index 0000000..340505e
--- /dev/null
+++ b/libchrome/base/metrics/histogram_snapshot_manager.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/metrics/histogram_snapshot_manager.h"
+
+#include <memory>
+
+#include "base/debug/alias.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() {
+}
+
+void HistogramSnapshotManager::PrepareDelta(HistogramBase* histogram) {
+  PrepareSamples(histogram, histogram->SnapshotDelta());
+}
+
+void HistogramSnapshotManager::PrepareFinalDelta(
+    const HistogramBase* histogram) {
+  PrepareSamples(histogram, histogram->SnapshotFinalDelta());
+}
+
+void HistogramSnapshotManager::PrepareSamples(
+    const HistogramBase* histogram,
+    std::unique_ptr<HistogramSamples> samples) {
+  DCHECK(histogram_flattener_);
+
+  // Get information known about this histogram. If it did not previously
+  // exist, one will be created and initialized.
+  SampleInfo* sample_info = &known_histograms_[histogram->name_hash()];
+
+  // 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.
+  uint32_t corruption = histogram->FindCorruption(*samples);
+  if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
+    // Extract fields useful during debug.
+    const BucketRanges* ranges =
+        static_cast<const Histogram*>(histogram)->bucket_ranges();
+    std::vector<HistogramBase::Sample> ranges_copy;
+    for (size_t i = 0; i < ranges->size(); ++i)
+      ranges_copy.push_back(ranges->range(i));
+    HistogramBase::Sample* ranges_ptr = &ranges_copy[0];
+    const char* histogram_name = histogram->histogram_name().c_str();
+    int32_t flags = histogram->flags();
+    // The checksum should have caught this, so crash separately if it didn't.
+    CHECK_NE(0U, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
+    CHECK(false);  // Crash for the bucket order corruption.
+    // Ensure that compiler keeps around pointers to |histogram| and its
+    // internal |bucket_ranges_| for any minidumps.
+    base::debug::Alias(&ranges_ptr);
+    base::debug::Alias(&histogram_name);
+    base::debug::Alias(&flags);
+  }
+  // Checksum corruption might not have caused order corruption.
+  CHECK_EQ(0U, 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->histogram_name()
+                << "\" has data corruption: " << corruption;
+    histogram_flattener_->InconsistencyDetected(
+        static_cast<HistogramBase::Inconsistency>(corruption));
+    // Don't record corrupt data to metrics services.
+    const uint32_t old_corruption = sample_info->inconsistencies;
+    if (old_corruption == (corruption | old_corruption))
+      return;  // We've already seen this corruption for this histogram.
+    sample_info->inconsistencies |= corruption;
+    histogram_flattener_->UniqueInconsistencyDetected(
+        static_cast<HistogramBase::Inconsistency>(corruption));
+    return;
+  }
+
+  if (samples->TotalCount() > 0)
+    histogram_flattener_->RecordDelta(*histogram, *samples);
+}
+
+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/libchrome/base/metrics/histogram_snapshot_manager.h b/libchrome/base/metrics/histogram_snapshot_manager.h
new file mode 100644
index 0000000..26fb93f
--- /dev/null
+++ b/libchrome/base/metrics/histogram_snapshot_manager.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_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.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|.
+  template <class ForwardHistogramIterator>
+  void PrepareDeltas(ForwardHistogramIterator begin,
+                     ForwardHistogramIterator end,
+                     HistogramBase::Flags flags_to_set,
+                     HistogramBase::Flags required_flags) {
+    for (ForwardHistogramIterator it = begin; it != end; ++it) {
+      (*it)->SetFlags(flags_to_set);
+      if (((*it)->flags() & required_flags) == required_flags)
+        PrepareDelta(*it);
+    }
+  }
+
+  // When the collection is not so simple as can be done using a single
+  // iterator, the steps can be performed separately. Call PerpareDelta()
+  // as many times as necessary. PrepareFinalDelta() works like PrepareDelta()
+  // except that it does not update the previous logged values and can thus
+  // be used with read-only files.
+  void PrepareDelta(HistogramBase* histogram);
+  void PrepareFinalDelta(const HistogramBase* histogram);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(HistogramSnapshotManagerTest, CheckMerge);
+
+  // During a snapshot, samples are acquired and aggregated. This structure
+  // contains all the information for a given histogram that persists between
+  // collections.
+  struct SampleInfo {
+    // The set of inconsistencies (flags) already seen for the histogram.
+    // See HistogramBase::Inconsistency for values.
+    uint32_t inconsistencies = 0;
+  };
+
+  // Capture and hold samples from a histogram. This does all the heavy
+  // lifting for PrepareDelta() and PrepareAbsolute().
+  void PrepareSamples(const HistogramBase* histogram,
+                      std::unique_ptr<HistogramSamples> samples);
+
+  // Try to detect and fix count inconsistency of logged samples.
+  void InspectLoggedSamplesInconsistency(
+      const HistogramSamples& new_snapshot,
+      HistogramSamples* logged_samples);
+
+  // For histograms, track what has been previously seen, indexed
+  // by the hash of the histogram name.
+  std::map<uint64_t, SampleInfo> known_histograms_;
+
+  // |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/libchrome/base/metrics/histogram_snapshot_manager_unittest.cc b/libchrome/base/metrics/histogram_snapshot_manager_unittest.cc
new file mode 100644
index 0000000..3c13e1a
--- /dev/null
+++ b/libchrome/base/metrics/histogram_snapshot_manager_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/metrics/histogram_snapshot_manager.h"
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/metrics/histogram_delta_serialization.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/stl_util.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());
+    // Use CHECK instead of ASSERT to get full stack-trace and thus origin.
+    CHECK(!ContainsKey(recorded_delta_histogram_sum_,
+                       histogram.histogram_name()));
+    // Keep pointer to snapshot for testing. This really isn't ideal but the
+    // snapshot-manager keeps the snapshot alive until it's "forgotten".
+    recorded_delta_histogram_sum_[histogram.histogram_name()] = snapshot.sum();
+  }
+
+  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);
+  }
+
+  void Reset() {
+    recorded_delta_histogram_names_.clear();
+    recorded_delta_histogram_sum_.clear();
+  }
+
+  std::vector<std::string> GetRecordedDeltaHistogramNames() {
+    return recorded_delta_histogram_names_;
+  }
+
+  int64_t GetRecordedDeltaHistogramSum(const std::string& name) {
+    EXPECT_TRUE(ContainsKey(recorded_delta_histogram_sum_, name));
+    return recorded_delta_histogram_sum_[name];
+  }
+
+ private:
+  std::vector<std::string> recorded_delta_histogram_names_;
+  std::map<std::string, int64_t> recorded_delta_histogram_sum_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramFlattenerDeltaRecorder);
+};
+
+class HistogramSnapshotManagerTest : public testing::Test {
+ protected:
+  HistogramSnapshotManagerTest()
+      : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()),
+        histogram_snapshot_manager_(&histogram_flattener_delta_recorder_) {}
+
+  ~HistogramSnapshotManagerTest() override {}
+
+  std::unique_ptr<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, 4);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(
+      StatisticsRecorder::begin(false), StatisticsRecorder::end(),
+      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, 4);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(
+      StatisticsRecorder::begin(false), StatisticsRecorder::end(),
+      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, 4);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(
+      StatisticsRecorder::begin(false), StatisticsRecorder::end(),
+      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/libchrome/base/metrics/histogram_unittest.cc b/libchrome/base/metrics/histogram_unittest.cc
new file mode 100644
index 0000000..5c2ca68
--- /dev/null
+++ b/libchrome/base/metrics/histogram_unittest.cc
@@ -0,0 +1,751 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <climits>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Test parameter indicates if a persistent memory allocator should be used
+// for histogram allocation. False will allocate histograms from the process
+// heap.
+class HistogramTest : public testing::TestWithParam<bool> {
+ protected:
+  const int32_t kAllocatorMemorySize = 8 << 20;  // 8 MiB
+
+  HistogramTest() : use_persistent_histogram_allocator_(GetParam()) {}
+
+  void SetUp() override {
+    if (use_persistent_histogram_allocator_)
+      CreatePersistentHistogramAllocator();
+
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override {
+    if (allocator_) {
+      ASSERT_FALSE(allocator_->IsFull());
+      ASSERT_FALSE(allocator_->IsCorrupt());
+    }
+    UninitializeStatisticsRecorder();
+    DestroyPersistentHistogramAllocator();
+  }
+
+  void InitializeStatisticsRecorder() {
+    DCHECK(!statistics_recorder_);
+    statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    statistics_recorder_.reset();
+  }
+
+  void CreatePersistentHistogramAllocator() {
+    // By getting the results-histogram before any persistent allocator
+    // is attached, that histogram is guaranteed not to be stored in
+    // any persistent memory segment (which simplifies some tests).
+    GlobalHistogramAllocator::GetCreateHistogramResultHistogram();
+
+    GlobalHistogramAllocator::CreateWithLocalMemory(
+        kAllocatorMemorySize, 0, "HistogramAllocatorTest");
+    allocator_ = GlobalHistogramAllocator::Get()->memory_allocator();
+  }
+
+  void DestroyPersistentHistogramAllocator() {
+    allocator_ = nullptr;
+    GlobalHistogramAllocator::ReleaseForTesting();
+  }
+
+  const bool use_persistent_histogram_allocator_;
+
+  std::unique_ptr<StatisticsRecorder> statistics_recorder_;
+  std::unique_ptr<char[]> allocator_memory_;
+  PersistentMemoryAllocator* allocator_ = nullptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HistogramTest);
+};
+
+// Run all HistogramTest cases with both heap and persistent memory.
+INSTANTIATE_TEST_CASE_P(HeapAndPersistent, HistogramTest, testing::Bool());
+
+
+// Check for basic syntax and use.
+TEST_P(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);
+
+  // Macros that create hitograms have an internal static variable which will
+  // continue to point to those from the very first run of this method even
+  // during subsequent runs.
+  static bool already_run = false;
+  if (already_run)
+    return;
+  already_run = true;
+
+  // 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_P(HistogramTest, NameMatchTest) {
+  // Macros that create hitograms have an internal static variable which will
+  // continue to point to those from the very first run of this method even
+  // during subsequent runs.
+  static bool already_run = false;
+  if (already_run)
+    return;
+  already_run = true;
+
+  LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags);
+
+  std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+  EXPECT_EQ(2, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCount(10));
+}
+
+// Check that delta calculations work correctly.
+TEST_P(HistogramTest, DeltaTest) {
+  HistogramBase* histogram =
+      Histogram::FactoryGet("DeltaHistogram", 1, 64, 8,
+                            HistogramBase::kNoFlags);
+  histogram->Add(1);
+  histogram->Add(10);
+  histogram->Add(50);
+
+  std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta();
+  EXPECT_EQ(3, samples->TotalCount());
+  EXPECT_EQ(1, samples->GetCount(1));
+  EXPECT_EQ(1, samples->GetCount(10));
+  EXPECT_EQ(1, samples->GetCount(50));
+  EXPECT_EQ(samples->TotalCount(), samples->redundant_count());
+
+  samples = histogram->SnapshotDelta();
+  EXPECT_EQ(0, samples->TotalCount());
+
+  histogram->Add(10);
+  histogram->Add(10);
+  samples = histogram->SnapshotDelta();
+  EXPECT_EQ(2, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCount(10));
+
+  samples = histogram->SnapshotDelta();
+  EXPECT_EQ(0, samples->TotalCount());
+}
+
+// Check that final-delta calculations work correctly.
+TEST_P(HistogramTest, FinalDeltaTest) {
+  HistogramBase* histogram =
+      Histogram::FactoryGet("FinalDeltaHistogram", 1, 64, 8,
+                            HistogramBase::kNoFlags);
+  histogram->Add(1);
+  histogram->Add(10);
+  histogram->Add(50);
+
+  std::unique_ptr<HistogramSamples> samples = histogram->SnapshotDelta();
+  EXPECT_EQ(3, samples->TotalCount());
+  EXPECT_EQ(1, samples->GetCount(1));
+  EXPECT_EQ(1, samples->GetCount(10));
+  EXPECT_EQ(1, samples->GetCount(50));
+  EXPECT_EQ(samples->TotalCount(), samples->redundant_count());
+
+  histogram->Add(2);
+  histogram->Add(50);
+
+  samples = histogram->SnapshotFinalDelta();
+  EXPECT_EQ(2, samples->TotalCount());
+  EXPECT_EQ(1, samples->GetCount(2));
+  EXPECT_EQ(1, samples->GetCount(50));
+  EXPECT_EQ(samples->TotalCount(), samples->redundant_count());
+}
+
+TEST_P(HistogramTest, ExponentialRangesTest) {
+  // Check that we got a nice exponential when there was enough room.
+  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_P(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_P(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_P(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_P(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));
+}
+
+TEST_P(HistogramTest, AddCountTest) {
+  const size_t kBucketCount = 50;
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("AddCountHistogram", 10, 100, kBucketCount,
+                            HistogramBase::kNoFlags));
+
+  histogram->AddCount(20, 15);
+  histogram->AddCount(30, 14);
+
+  std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+  EXPECT_EQ(29, samples->TotalCount());
+  EXPECT_EQ(15, samples->GetCount(20));
+  EXPECT_EQ(14, samples->GetCount(30));
+
+  histogram->AddCount(20, 25);
+  histogram->AddCount(30, 24);
+
+  std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples();
+  EXPECT_EQ(78, samples2->TotalCount());
+  EXPECT_EQ(40, samples2->GetCount(20));
+  EXPECT_EQ(38, samples2->GetCount(30));
+}
+
+TEST_P(HistogramTest, AddCount_LargeValuesDontOverflow) {
+  const size_t kBucketCount = 50;
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("AddCountHistogram", 10, 1000000000, kBucketCount,
+                            HistogramBase::kNoFlags));
+
+  histogram->AddCount(200000000, 15);
+  histogram->AddCount(300000000, 14);
+
+  std::unique_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+  EXPECT_EQ(29, samples->TotalCount());
+  EXPECT_EQ(15, samples->GetCount(200000000));
+  EXPECT_EQ(14, samples->GetCount(300000000));
+
+  histogram->AddCount(200000000, 25);
+  histogram->AddCount(300000000, 24);
+
+  std::unique_ptr<HistogramSamples> samples2 = histogram->SnapshotSamples();
+  EXPECT_EQ(78, samples2->TotalCount());
+  EXPECT_EQ(40, samples2->GetCount(200000000));
+  EXPECT_EQ(38, samples2->GetCount(300000000));
+  EXPECT_EQ(19400000000LL, samples2->sum());
+}
+
+// Make sure histogram handles out-of-bounds data gracefully.
+TEST_P(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.
+  std::unique_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.
+  std::unique_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_P(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.
+  std::unique_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  for (int i = 0; i < 8; i++)
+    EXPECT_EQ(i + 1, samples->GetCountAtIndex(i));
+}
+
+TEST_P(HistogramTest, CorruptSampleCounts) {
+  // The internal code creates histograms via macros and thus keeps static
+  // pointers to them. If those pointers are to persistent memory which will
+  // be free'd then any following calls to that code will crash with a
+  // segmentation violation.
+  if (use_persistent_histogram_allocator_)
+    return;
+
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  // Add some samples.
+  histogram->Add(20);
+  histogram->Add(40);
+
+  std::unique_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_P(HistogramTest, CorruptBucketBounds) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  std::unique_ptr<HistogramSamples> snapshot = histogram->SnapshotSamples();
+  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(0U, 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_P(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 & ~HistogramBase::kIsPersistent);
+
+  int min;
+  EXPECT_TRUE(iter.ReadInt(&min));
+  EXPECT_EQ(1, min);
+
+  int max;
+  EXPECT_TRUE(iter.ReadInt(&max));
+  EXPECT_EQ(64, max);
+
+  uint32_t bucket_count;
+  EXPECT_TRUE(iter.ReadUInt32(&bucket_count));
+  EXPECT_EQ(8u, bucket_count);
+
+  uint32_t 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_P(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;
+  uint32_t bucket_count;
+  uint32_t ui32;
+  EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
+              iter.ReadInt(&i) && iter.ReadInt(&i) &&
+              iter.ReadUInt32(&bucket_count) && iter.ReadUInt32(&ui32));
+  EXPECT_EQ(3u, 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_P(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);
+}
+
+TEST_P(HistogramTest, FactoryTime) {
+  const int kTestCreateCount = 1 << 14;  // Must be power-of-2.
+  const int kTestLookupCount = 100000;
+  const int kTestAddCount = 1000000;
+
+  // Create all histogram names in advance for accurate timing below.
+  std::vector<std::string> histogram_names;
+  for (int i = 0; i < kTestCreateCount; ++i) {
+    histogram_names.push_back(
+        StringPrintf("TestHistogram.%d", i % kTestCreateCount));
+  }
+
+  // Calculate cost of creating histograms.
+  TimeTicks create_start = TimeTicks::Now();
+  for (int i = 0; i < kTestCreateCount; ++i) {
+    Histogram::FactoryGet(histogram_names[i], 1, 100, 10,
+                          HistogramBase::kNoFlags);
+  }
+  TimeDelta create_ticks = TimeTicks::Now() - create_start;
+  int64_t create_ms = create_ticks.InMilliseconds();
+
+  VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms
+          << "ms or about "
+          << (create_ms * 1000000) / kTestCreateCount
+          << "ns each.";
+
+  // Calculate cost of looking up existing histograms.
+  TimeTicks lookup_start = TimeTicks::Now();
+  for (int i = 0; i < kTestLookupCount; ++i) {
+    // 6007 is co-prime with kTestCreateCount and so will do lookups in an
+    // order less likely to be cacheable (but still hit them all) should the
+    // underlying storage use the exact histogram name as the key.
+    const int i_mult = 6007;
+    static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big");
+    int index = (i * i_mult) & (kTestCreateCount - 1);
+    Histogram::FactoryGet(histogram_names[index], 1, 100, 10,
+                          HistogramBase::kNoFlags);
+  }
+  TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start;
+  int64_t lookup_ms = lookup_ticks.InMilliseconds();
+
+  VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms
+          << "ms or about "
+          << (lookup_ms * 1000000) / kTestLookupCount
+          << "ns each.";
+
+  // Calculate cost of accessing histograms.
+  HistogramBase* histogram = Histogram::FactoryGet(
+      histogram_names[0], 1, 100, 10, HistogramBase::kNoFlags);
+  ASSERT_TRUE(histogram);
+  TimeTicks add_start = TimeTicks::Now();
+  for (int i = 0; i < kTestAddCount; ++i)
+    histogram->Add(i & 127);
+  TimeDelta add_ticks = TimeTicks::Now() - add_start;
+  int64_t add_ms = add_ticks.InMilliseconds();
+
+  VLOG(1) << kTestAddCount << " histogram adds took " << add_ms
+          << "ms or about "
+          << (add_ms * 1000000) / kTestAddCount
+          << "ns each.";
+}
+
+#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/libchrome/base/metrics/metrics_hashes.cc b/libchrome/base/metrics/metrics_hashes.cc
new file mode 100644
index 0000000..5672b06
--- /dev/null
+++ b/libchrome/base/metrics/metrics_hashes.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/metrics/metrics_hashes.h"
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/sys_byteorder.h"
+
+namespace base {
+
+namespace {
+
+// Converts the 8-byte prefix of an MD5 hash into a uint64_t value.
+inline uint64_t DigestToUInt64(const base::MD5Digest& digest) {
+  uint64_t value;
+  DCHECK_GE(sizeof(digest.a), sizeof(value));
+  memcpy(&value, digest.a, sizeof(value));
+  return base::NetToHost64(value);
+}
+
+}  // namespace
+
+uint64_t HashMetricName(base::StringPiece name) {
+  base::MD5Digest digest;
+  base::MD5Sum(name.data(), name.size(), &digest);
+  return DigestToUInt64(digest);
+}
+
+}  // namespace metrics
diff --git a/libchrome/base/metrics/metrics_hashes.h b/libchrome/base/metrics/metrics_hashes.h
new file mode 100644
index 0000000..d05c4ba
--- /dev/null
+++ b/libchrome/base/metrics/metrics_hashes.h
@@ -0,0 +1,21 @@
+// 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_METRICS_HASHES_H_
+#define BASE_METRICS_METRICS_HASHES_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Computes a uint64_t hash of a given string based on its MD5 hash. Suitable
+// for metric names.
+BASE_EXPORT uint64_t HashMetricName(base::StringPiece name);
+
+}  // namespace metrics
+
+#endif  // BASE_METRICS_METRICS_HASHES_H_
diff --git a/libchrome/base/metrics/metrics_hashes_unittest.cc b/libchrome/base/metrics/metrics_hashes_unittest.cc
new file mode 100644
index 0000000..aea254e
--- /dev/null
+++ b/libchrome/base/metrics/metrics_hashes_unittest.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/metrics/metrics_hashes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/format_macros.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Make sure our ID hashes are the same as what we see on the server side.
+TEST(MetricsUtilTest, HashMetricName) {
+  static const struct {
+    std::string input;
+    std::string output;
+  } cases[] = {
+    {"Back", "0x0557fa923dcee4d0"},
+    {"Forward", "0x67d2f6740a8eaebf"},
+    {"NewTab", "0x290eb683f96572f1"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64_t hash = HashMetricName(cases[i].input);
+    std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash);
+    EXPECT_EQ(cases[i].output, hash_hex);
+  }
+}
+
+}  // namespace metrics
diff --git a/libchrome/base/metrics/persistent_histogram_allocator.cc b/libchrome/base/metrics/persistent_histogram_allocator.cc
new file mode 100644
index 0000000..5af3486
--- /dev/null
+++ b/libchrome/base/metrics/persistent_histogram_allocator.cc
@@ -0,0 +1,866 @@
+// Copyright 2016 The Chromium Authors. All 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/persistent_histogram_allocator.h"
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/persistent_sample_map.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+namespace {
+
+// Name of histogram for storing results of local operations.
+const char kResultHistogram[] = "UMA.CreatePersistentHistogram.Result";
+
+// Type identifiers used when storing in persistent memory so they can be
+// identified during extraction; the first 4 bytes of the SHA1 of the name
+// is used as a unique integer. A "version number" is added to the base
+// so that, if the structure of that object changes, stored older versions
+// will be safely ignored.
+enum : uint32_t {
+  kTypeIdHistogram   = 0xF1645910 + 2,  // SHA1(Histogram)   v2
+  kTypeIdRangesArray = 0xBCEA225A + 1,  // SHA1(RangesArray) v1
+  kTypeIdCountsArray = 0x53215530 + 1,  // SHA1(CountsArray) v1
+};
+
+// The current globally-active persistent allocator for all new histograms.
+// The object held here will obviously not be destructed at process exit
+// but that's best since PersistentMemoryAllocator objects (that underlie
+// GlobalHistogramAllocator objects) are explicitly forbidden from doing
+// anything essential at exit anyway due to the fact that they depend on data
+// managed elsewhere and which could be destructed first.
+GlobalHistogramAllocator* g_allocator = nullptr;
+
+// Take an array of range boundaries and create a proper BucketRanges object
+// which is returned to the caller. A return of nullptr indicates that the
+// passed boundaries are invalid.
+std::unique_ptr<BucketRanges> CreateRangesFromData(
+    HistogramBase::Sample* ranges_data,
+    uint32_t ranges_checksum,
+    size_t count) {
+  // To avoid racy destruction at shutdown, the following may be leaked.
+  std::unique_ptr<BucketRanges> ranges(new BucketRanges(count));
+  DCHECK_EQ(count, ranges->size());
+  for (size_t i = 0; i < count; ++i) {
+    if (i > 0 && ranges_data[i] <= ranges_data[i - 1])
+      return nullptr;
+    ranges->set_range(i, ranges_data[i]);
+  }
+
+  ranges->ResetChecksum();
+  if (ranges->checksum() != ranges_checksum)
+    return nullptr;
+
+  return ranges;
+}
+
+// Calculate the number of bytes required to store all of a histogram's
+// "counts". This will return zero (0) if |bucket_count| is not valid.
+size_t CalculateRequiredCountsBytes(size_t bucket_count) {
+  // 2 because each "sample count" also requires a backup "logged count"
+  // used for calculating the delta during snapshot operations.
+  const size_t kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount);
+
+  // If the |bucket_count| is such that it would overflow the return type,
+  // perhaps as the result of a malicious actor, then return zero to
+  // indicate the problem to the caller.
+  if (bucket_count > std::numeric_limits<size_t>::max() / kBytesPerBucket)
+    return 0;
+
+  return bucket_count * kBytesPerBucket;
+}
+
+}  // namespace
+
+const Feature kPersistentHistogramsFeature{
+  "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
+};
+
+
+PersistentSparseHistogramDataManager::PersistentSparseHistogramDataManager(
+    PersistentMemoryAllocator* allocator)
+    : allocator_(allocator), record_iterator_(allocator) {}
+
+PersistentSparseHistogramDataManager::~PersistentSparseHistogramDataManager() {}
+
+PersistentSampleMapRecords*
+PersistentSparseHistogramDataManager::UseSampleMapRecords(uint64_t id,
+                                                          const void* user) {
+  base::AutoLock auto_lock(lock_);
+  return GetSampleMapRecordsWhileLocked(id)->Acquire(user);
+}
+
+PersistentSampleMapRecords*
+PersistentSparseHistogramDataManager::GetSampleMapRecordsWhileLocked(
+    uint64_t id) {
+  lock_.AssertAcquired();
+
+  auto found = sample_records_.find(id);
+  if (found != sample_records_.end())
+    return found->second.get();
+
+  std::unique_ptr<PersistentSampleMapRecords>& samples = sample_records_[id];
+  samples = WrapUnique(new PersistentSampleMapRecords(this, id));
+  return samples.get();
+}
+
+bool PersistentSparseHistogramDataManager::LoadRecords(
+    PersistentSampleMapRecords* sample_map_records) {
+  // DataManager must be locked in order to access the found_ field of any
+  // PersistentSampleMapRecords object.
+  base::AutoLock auto_lock(lock_);
+  bool found = false;
+
+  // If there are already "found" entries for the passed object, move them.
+  if (!sample_map_records->found_.empty()) {
+    sample_map_records->records_.reserve(sample_map_records->records_.size() +
+                                         sample_map_records->found_.size());
+    sample_map_records->records_.insert(sample_map_records->records_.end(),
+                                        sample_map_records->found_.begin(),
+                                        sample_map_records->found_.end());
+    sample_map_records->found_.clear();
+    found = true;
+  }
+
+  // Acquiring a lock is a semi-expensive operation so load some records with
+  // each call. More than this number may be loaded if it takes longer to
+  // find at least one matching record for the passed object.
+  const int kMinimumNumberToLoad = 10;
+  const uint64_t match_id = sample_map_records->sample_map_id_;
+
+  // Loop while no enty is found OR we haven't yet loaded the minimum number.
+  // This will continue reading even after a match is found.
+  for (int count = 0; !found || count < kMinimumNumberToLoad; ++count) {
+    // Get the next sample-record. The iterator will always resume from where
+    // it left off even if it previously had nothing further to return.
+    uint64_t found_id;
+    PersistentMemoryAllocator::Reference ref =
+        PersistentSampleMap::GetNextPersistentRecord(record_iterator_,
+                                                     &found_id);
+
+    // Stop immediately if there are none.
+    if (!ref)
+      break;
+
+    // The sample-record could be for any sparse histogram. Add the reference
+    // to the appropriate collection for later use.
+    if (found_id == match_id) {
+      sample_map_records->records_.push_back(ref);
+      found = true;
+    } else {
+      PersistentSampleMapRecords* samples =
+          GetSampleMapRecordsWhileLocked(found_id);
+      DCHECK(samples);
+      samples->found_.push_back(ref);
+    }
+  }
+
+  return found;
+}
+
+
+PersistentSampleMapRecords::PersistentSampleMapRecords(
+    PersistentSparseHistogramDataManager* data_manager,
+    uint64_t sample_map_id)
+    : data_manager_(data_manager), sample_map_id_(sample_map_id) {}
+
+PersistentSampleMapRecords::~PersistentSampleMapRecords() {}
+
+PersistentSampleMapRecords* PersistentSampleMapRecords::Acquire(
+    const void* user) {
+  DCHECK(!user_);
+  user_ = user;
+  seen_ = 0;
+  return this;
+}
+
+void PersistentSampleMapRecords::Release(const void* user) {
+  DCHECK_EQ(user_, user);
+  user_ = nullptr;
+}
+
+PersistentMemoryAllocator::Reference PersistentSampleMapRecords::GetNext() {
+  DCHECK(user_);
+
+  // If there are no unseen records, lock and swap in all the found ones.
+  if (records_.size() == seen_) {
+    if (!data_manager_->LoadRecords(this))
+      return false;
+  }
+
+  // Return the next record. Records *must* be returned in the same order
+  // they are found in the persistent memory in order to ensure that all
+  // objects using this data always have the same state. Race conditions
+  // can cause duplicate records so using the "first found" is the only
+  // guarantee that all objects always access the same one.
+  DCHECK_LT(seen_, records_.size());
+  return records_[seen_++];
+}
+
+PersistentMemoryAllocator::Reference PersistentSampleMapRecords::CreateNew(
+    HistogramBase::Sample value) {
+  return PersistentSampleMap::CreatePersistentRecord(data_manager_->allocator_,
+                                                     sample_map_id_, value);
+}
+
+
+// This data will be held in persistent memory in order for processes to
+// locate and use histograms created elsewhere.
+struct PersistentHistogramAllocator::PersistentHistogramData {
+  int32_t histogram_type;
+  int32_t flags;
+  int32_t minimum;
+  int32_t maximum;
+  uint32_t bucket_count;
+  PersistentMemoryAllocator::Reference ranges_ref;
+  uint32_t ranges_checksum;
+  PersistentMemoryAllocator::Reference counts_ref;
+  HistogramSamples::Metadata samples_metadata;
+  HistogramSamples::Metadata logged_metadata;
+
+  // Space for the histogram name will be added during the actual allocation
+  // request. This must be the last field of the structure. A zero-size array
+  // or a "flexible" array would be preferred but is not (yet) valid C++.
+  char name[1];
+};
+
+PersistentHistogramAllocator::Iterator::Iterator(
+    PersistentHistogramAllocator* allocator)
+    : allocator_(allocator), memory_iter_(allocator->memory_allocator()) {}
+
+std::unique_ptr<HistogramBase>
+PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) {
+  PersistentMemoryAllocator::Reference ref;
+  while ((ref = memory_iter_.GetNextOfType(kTypeIdHistogram)) != 0) {
+    if (ref != ignore)
+      return allocator_->GetHistogram(ref);
+  }
+  return nullptr;
+}
+
+
+PersistentHistogramAllocator::PersistentHistogramAllocator(
+    std::unique_ptr<PersistentMemoryAllocator> memory)
+    : memory_allocator_(std::move(memory)),
+      sparse_histogram_data_manager_(memory_allocator_.get()) {}
+
+PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
+
+std::unique_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram(
+    Reference ref) {
+  // Unfortunately, the histogram "pickle" methods cannot be used as part of
+  // the persistance because the deserialization methods always create local
+  // count data (while these must reference the persistent counts) and always
+  // add it to the local list of known histograms (while these may be simple
+  // references to histograms in other processes).
+  PersistentHistogramData* histogram_data =
+      memory_allocator_->GetAsObject<PersistentHistogramData>(
+          ref, kTypeIdHistogram);
+  size_t length = memory_allocator_->GetAllocSize(ref);
+  if (!histogram_data ||
+      reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA);
+    NOTREACHED();
+    return nullptr;
+  }
+  return CreateHistogram(histogram_data);
+}
+
+std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
+    HistogramType histogram_type,
+    const std::string& name,
+    int minimum,
+    int maximum,
+    const BucketRanges* bucket_ranges,
+    int32_t flags,
+    Reference* ref_ptr) {
+  // If the allocator is corrupt, don't waste time trying anything else.
+  // This also allows differentiating on the dashboard between allocations
+  // failed due to a corrupt allocator and the number of process instances
+  // with one, the latter being idicated by "newly corrupt", below.
+  if (memory_allocator_->IsCorrupt()) {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT);
+    return nullptr;
+  }
+
+  // Create the metadata necessary for a persistent sparse histogram. This
+  // is done first because it is a small subset of what is required for
+  // other histograms.
+  PersistentMemoryAllocator::Reference histogram_ref =
+      memory_allocator_->Allocate(
+          offsetof(PersistentHistogramData, name) + name.length() + 1,
+          kTypeIdHistogram);
+  PersistentHistogramData* histogram_data =
+      memory_allocator_->GetAsObject<PersistentHistogramData>(histogram_ref,
+                                                              kTypeIdHistogram);
+  if (histogram_data) {
+    memcpy(histogram_data->name, name.c_str(), name.size() + 1);
+    histogram_data->histogram_type = histogram_type;
+    histogram_data->flags = flags | HistogramBase::kIsPersistent;
+  }
+
+  // Create the remaining metadata necessary for regular histograms.
+  if (histogram_type != SPARSE_HISTOGRAM) {
+    size_t bucket_count = bucket_ranges->bucket_count();
+    size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count);
+    if (counts_bytes == 0) {
+      // |bucket_count| was out-of-range.
+      NOTREACHED();
+      return nullptr;
+    }
+
+    size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample);
+    PersistentMemoryAllocator::Reference counts_ref =
+        memory_allocator_->Allocate(counts_bytes, kTypeIdCountsArray);
+    PersistentMemoryAllocator::Reference ranges_ref =
+        memory_allocator_->Allocate(ranges_bytes, kTypeIdRangesArray);
+    HistogramBase::Sample* ranges_data =
+        memory_allocator_->GetAsObject<HistogramBase::Sample>(
+            ranges_ref, kTypeIdRangesArray);
+
+    // Only continue here if all allocations were successful. If they weren't,
+    // there is no way to free the space but that's not really a problem since
+    // the allocations only fail because the space is full or corrupt and so
+    // any future attempts will also fail.
+    if (counts_ref && ranges_data && histogram_data) {
+      for (size_t i = 0; i < bucket_ranges->size(); ++i)
+        ranges_data[i] = bucket_ranges->range(i);
+
+      histogram_data->minimum = minimum;
+      histogram_data->maximum = maximum;
+      // |bucket_count| must fit within 32-bits or the allocation of the counts
+      // array would have failed for being too large; the allocator supports
+      // less than 4GB total size.
+      histogram_data->bucket_count = static_cast<uint32_t>(bucket_count);
+      histogram_data->ranges_ref = ranges_ref;
+      histogram_data->ranges_checksum = bucket_ranges->checksum();
+      histogram_data->counts_ref = counts_ref;
+    } else {
+      histogram_data = nullptr;  // Clear this for proper handling below.
+    }
+  }
+
+  if (histogram_data) {
+    // Create the histogram using resources in persistent memory. This ends up
+    // resolving the "ref" values stored in histogram_data instad of just
+    // using what is already known above but avoids duplicating the switch
+    // statement here and serves as a double-check that everything is
+    // correct before commiting the new histogram to persistent space.
+    std::unique_ptr<HistogramBase> histogram = CreateHistogram(histogram_data);
+    DCHECK(histogram);
+    if (ref_ptr != nullptr)
+      *ref_ptr = histogram_ref;
+
+    // By storing the reference within the allocator to this histogram, the
+    // next import (which will happen before the next histogram creation)
+    // will know to skip it.
+    // See also the comment in ImportHistogramsToStatisticsRecorder().
+    subtle::NoBarrier_Store(&last_created_, histogram_ref);
+    return histogram;
+  }
+
+  CreateHistogramResultType result;
+  if (memory_allocator_->IsCorrupt()) {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT);
+    result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT;
+  } else if (memory_allocator_->IsFull()) {
+    result = CREATE_HISTOGRAM_ALLOCATOR_FULL;
+  } else {
+    result = CREATE_HISTOGRAM_ALLOCATOR_ERROR;
+  }
+  RecordCreateHistogramResult(result);
+  NOTREACHED() << "error=" << result;
+
+  return nullptr;
+}
+
+void PersistentHistogramAllocator::FinalizeHistogram(Reference ref,
+                                                     bool registered) {
+  // If the created persistent histogram was registered then it needs to
+  // be marked as "iterable" in order to be found by other processes.
+  if (registered)
+    memory_allocator_->MakeIterable(ref);
+  // If it wasn't registered then a race condition must have caused
+  // two to be created. The allocator does not support releasing the
+  // acquired memory so just change the type to be empty.
+  else
+    memory_allocator_->ChangeType(ref, 0, kTypeIdHistogram);
+}
+
+void PersistentHistogramAllocator::MergeHistogramDeltaToStatisticsRecorder(
+    HistogramBase* histogram) {
+  DCHECK(histogram);
+
+  HistogramBase* existing = GetOrCreateStatisticsRecorderHistogram(histogram);
+  if (!existing) {
+    // The above should never fail but if it does, no real harm is done.
+    // The data won't be merged but it also won't be recorded as merged
+    // so a future try, if successful, will get what was missed. If it
+    // continues to fail, some metric data will be lost but that is better
+    // than crashing.
+    NOTREACHED();
+    return;
+  }
+
+  // Merge the delta from the passed object to the one in the SR.
+  existing->AddSamples(*histogram->SnapshotDelta());
+}
+
+void PersistentHistogramAllocator::MergeHistogramFinalDeltaToStatisticsRecorder(
+    const HistogramBase* histogram) {
+  DCHECK(histogram);
+
+  HistogramBase* existing = GetOrCreateStatisticsRecorderHistogram(histogram);
+  if (!existing) {
+    // The above should never fail but if it does, no real harm is done.
+    // Some metric data will be lost but that is better than crashing.
+    NOTREACHED();
+    return;
+  }
+
+  // Merge the delta from the passed object to the one in the SR.
+  existing->AddSamples(*histogram->SnapshotFinalDelta());
+}
+
+PersistentSampleMapRecords* PersistentHistogramAllocator::UseSampleMapRecords(
+    uint64_t id,
+    const void* user) {
+  return sparse_histogram_data_manager_.UseSampleMapRecords(id, user);
+}
+
+void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) {
+  memory_allocator_->CreateTrackingHistograms(name);
+}
+
+void PersistentHistogramAllocator::UpdateTrackingHistograms() {
+  memory_allocator_->UpdateTrackingHistograms();
+}
+
+void PersistentHistogramAllocator::ClearLastCreatedReferenceForTesting() {
+  subtle::NoBarrier_Store(&last_created_, 0);
+}
+
+// static
+HistogramBase*
+PersistentHistogramAllocator::GetCreateHistogramResultHistogram() {
+  // Get the histogram in which create-results are stored. This is copied
+  // almost exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with
+  // added code to prevent recursion (a likely occurance because the creation
+  // of a new a histogram can end up calling this.)
+  static base::subtle::AtomicWord atomic_histogram_pointer = 0;
+  HistogramBase* histogram_pointer =
+      reinterpret_cast<HistogramBase*>(
+          base::subtle::Acquire_Load(&atomic_histogram_pointer));
+  if (!histogram_pointer) {
+    // It's possible for multiple threads to make it here in parallel but
+    // they'll always return the same result as there is a mutex in the Get.
+    // The purpose of the "initialized" variable is just to ensure that
+    // the same thread doesn't recurse which is also why it doesn't have
+    // to be atomic.
+    static bool initialized = false;
+    if (!initialized) {
+      initialized = true;
+      if (g_allocator) {
+// Don't log in release-with-asserts builds, otherwise the test_installer step
+// fails because this code writes to a log file before the installer code had a
+// chance to set the log file's location.
+#if !defined(DCHECK_ALWAYS_ON)
+        DLOG(WARNING) << "Creating the results-histogram inside persistent"
+                      << " memory can cause future allocations to crash if"
+                      << " that memory is ever released (for testing).";
+#endif
+      }
+
+      histogram_pointer = LinearHistogram::FactoryGet(
+          kResultHistogram, 1, CREATE_HISTOGRAM_MAX, CREATE_HISTOGRAM_MAX + 1,
+          HistogramBase::kUmaTargetedHistogramFlag);
+      base::subtle::Release_Store(
+          &atomic_histogram_pointer,
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+    }
+  }
+  return histogram_pointer;
+}
+
+std::unique_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
+    PersistentHistogramData* histogram_data_ptr) {
+  if (!histogram_data_ptr) {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER);
+    NOTREACHED();
+    return nullptr;
+  }
+
+  // Sparse histograms are quite different so handle them as a special case.
+  if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) {
+    std::unique_ptr<HistogramBase> histogram =
+        SparseHistogram::PersistentCreate(this, histogram_data_ptr->name,
+                                          &histogram_data_ptr->samples_metadata,
+                                          &histogram_data_ptr->logged_metadata);
+    DCHECK(histogram);
+    histogram->SetFlags(histogram_data_ptr->flags);
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS);
+    return histogram;
+  }
+
+  // Copy the histogram_data to local storage because anything in persistent
+  // memory cannot be trusted as it could be changed at any moment by a
+  // malicious actor that shares access. The contents of histogram_data are
+  // validated below; the local copy is to ensure that the contents cannot
+  // be externally changed between validation and use.
+  PersistentHistogramData histogram_data = *histogram_data_ptr;
+
+  HistogramBase::Sample* ranges_data =
+      memory_allocator_->GetAsObject<HistogramBase::Sample>(
+          histogram_data.ranges_ref, kTypeIdRangesArray);
+
+  const uint32_t max_buckets =
+      std::numeric_limits<uint32_t>::max() / sizeof(HistogramBase::Sample);
+  size_t required_bytes =
+      (histogram_data.bucket_count + 1) * sizeof(HistogramBase::Sample);
+  size_t allocated_bytes =
+      memory_allocator_->GetAllocSize(histogram_data.ranges_ref);
+  if (!ranges_data || histogram_data.bucket_count < 2 ||
+      histogram_data.bucket_count >= max_buckets ||
+      allocated_bytes < required_bytes) {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
+    NOTREACHED();
+    return nullptr;
+  }
+
+  std::unique_ptr<const BucketRanges> created_ranges =
+      CreateRangesFromData(ranges_data, histogram_data.ranges_checksum,
+                           histogram_data.bucket_count + 1);
+  if (!created_ranges) {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
+    NOTREACHED();
+    return nullptr;
+  }
+  const BucketRanges* ranges =
+      StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
+          created_ranges.release());
+
+  HistogramBase::AtomicCount* counts_data =
+      memory_allocator_->GetAsObject<HistogramBase::AtomicCount>(
+          histogram_data.counts_ref, kTypeIdCountsArray);
+  size_t counts_bytes =
+      CalculateRequiredCountsBytes(histogram_data.bucket_count);
+  if (!counts_data || counts_bytes == 0 ||
+      memory_allocator_->GetAllocSize(histogram_data.counts_ref) <
+          counts_bytes) {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY);
+    NOTREACHED();
+    return nullptr;
+  }
+
+  // After the main "counts" array is a second array using for storing what
+  // was previously logged. This is used to calculate the "delta" during
+  // snapshot operations.
+  HistogramBase::AtomicCount* logged_data =
+      counts_data + histogram_data.bucket_count;
+
+  std::string name(histogram_data_ptr->name);
+  std::unique_ptr<HistogramBase> histogram;
+  switch (histogram_data.histogram_type) {
+    case HISTOGRAM:
+      histogram = Histogram::PersistentCreate(
+          name, histogram_data.minimum, histogram_data.maximum, ranges,
+          counts_data, logged_data, histogram_data.bucket_count,
+          &histogram_data_ptr->samples_metadata,
+          &histogram_data_ptr->logged_metadata);
+      DCHECK(histogram);
+      break;
+    case LINEAR_HISTOGRAM:
+      histogram = LinearHistogram::PersistentCreate(
+          name, histogram_data.minimum, histogram_data.maximum, ranges,
+          counts_data, logged_data, histogram_data.bucket_count,
+          &histogram_data_ptr->samples_metadata,
+          &histogram_data_ptr->logged_metadata);
+      DCHECK(histogram);
+      break;
+    case BOOLEAN_HISTOGRAM:
+      histogram = BooleanHistogram::PersistentCreate(
+          name, ranges, counts_data, logged_data,
+          &histogram_data_ptr->samples_metadata,
+          &histogram_data_ptr->logged_metadata);
+      DCHECK(histogram);
+      break;
+    case CUSTOM_HISTOGRAM:
+      histogram = CustomHistogram::PersistentCreate(
+          name, ranges, counts_data, logged_data, histogram_data.bucket_count,
+          &histogram_data_ptr->samples_metadata,
+          &histogram_data_ptr->logged_metadata);
+      DCHECK(histogram);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  if (histogram) {
+    DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType());
+    histogram->SetFlags(histogram_data.flags);
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS);
+  } else {
+    RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE);
+  }
+
+  return histogram;
+}
+
+HistogramBase*
+PersistentHistogramAllocator::GetOrCreateStatisticsRecorderHistogram(
+    const HistogramBase* histogram) {
+  // This should never be called on the global histogram allocator as objects
+  // created there are already within the global statistics recorder.
+  DCHECK_NE(g_allocator, this);
+  DCHECK(histogram);
+
+  HistogramBase* existing =
+      StatisticsRecorder::FindHistogram(histogram->histogram_name());
+  if (existing)
+    return existing;
+
+  // Adding the passed histogram to the SR would cause a problem if the
+  // allocator that holds it eventually goes away. Instead, create a new
+  // one from a serialized version.
+  base::Pickle pickle;
+  if (!histogram->SerializeInfo(&pickle))
+    return nullptr;
+  PickleIterator iter(pickle);
+  existing = DeserializeHistogramInfo(&iter);
+  if (!existing)
+    return nullptr;
+
+  // Make sure there is no "serialization" flag set.
+  DCHECK_EQ(0, existing->flags() & HistogramBase::kIPCSerializationSourceFlag);
+  // Record the newly created histogram in the SR.
+  return StatisticsRecorder::RegisterOrDeleteDuplicate(existing);
+}
+
+// static
+void PersistentHistogramAllocator::RecordCreateHistogramResult(
+    CreateHistogramResultType result) {
+  HistogramBase* result_histogram = GetCreateHistogramResultHistogram();
+  if (result_histogram)
+    result_histogram->Add(result);
+}
+
+GlobalHistogramAllocator::~GlobalHistogramAllocator() {}
+
+// static
+void GlobalHistogramAllocator::CreateWithPersistentMemory(
+    void* base,
+    size_t size,
+    size_t page_size,
+    uint64_t id,
+    StringPiece name) {
+  Set(WrapUnique(new GlobalHistogramAllocator(
+      WrapUnique(new PersistentMemoryAllocator(
+          base, size, page_size, id, name, false)))));
+}
+
+// static
+void GlobalHistogramAllocator::CreateWithLocalMemory(
+    size_t size,
+    uint64_t id,
+    StringPiece name) {
+  Set(WrapUnique(new GlobalHistogramAllocator(
+      WrapUnique(new LocalPersistentMemoryAllocator(size, id, name)))));
+}
+
+#if !defined(OS_NACL)
+// static
+void GlobalHistogramAllocator::CreateWithFile(
+    const FilePath& file_path,
+    size_t size,
+    uint64_t id,
+    StringPiece name) {
+  bool exists = PathExists(file_path);
+  File file(
+      file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_SHARE_DELETE |
+                 File::FLAG_READ | File::FLAG_WRITE);
+
+  std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
+  if (exists) {
+    mmfile->Initialize(std::move(file), MemoryMappedFile::READ_WRITE);
+  } else {
+    mmfile->Initialize(std::move(file), {0, static_cast<int64_t>(size)},
+                       MemoryMappedFile::READ_WRITE_EXTEND);
+  }
+  if (!mmfile->IsValid() ||
+      !FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) {
+    NOTREACHED();
+    return;
+  }
+
+  Set(WrapUnique(new GlobalHistogramAllocator(
+      WrapUnique(new FilePersistentMemoryAllocator(
+          std::move(mmfile), size, id, name, false)))));
+}
+#endif
+
+// static
+void GlobalHistogramAllocator::CreateWithSharedMemory(
+    std::unique_ptr<SharedMemory> memory,
+    size_t size,
+    uint64_t /*id*/,
+    StringPiece /*name*/) {
+  if ((!memory->memory() && !memory->Map(size)) ||
+      !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*memory)) {
+    NOTREACHED();
+    return;
+  }
+
+  DCHECK_LE(memory->mapped_size(), size);
+  Set(WrapUnique(new GlobalHistogramAllocator(
+      WrapUnique(new SharedPersistentMemoryAllocator(
+          std::move(memory), 0, StringPiece(), /*readonly=*/false)))));
+}
+
+// static
+void GlobalHistogramAllocator::CreateWithSharedMemoryHandle(
+    const SharedMemoryHandle& handle,
+    size_t size) {
+  std::unique_ptr<SharedMemory> shm(
+      new SharedMemory(handle, /*readonly=*/false));
+  if (!shm->Map(size) ||
+      !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*shm)) {
+    NOTREACHED();
+    return;
+  }
+
+  Set(WrapUnique(new GlobalHistogramAllocator(
+      WrapUnique(new SharedPersistentMemoryAllocator(
+          std::move(shm), 0, StringPiece(), /*readonly=*/false)))));
+}
+
+// static
+void GlobalHistogramAllocator::Set(
+    std::unique_ptr<GlobalHistogramAllocator> allocator) {
+  // Releasing or changing an allocator is extremely dangerous because it
+  // likely has histograms stored within it. If the backing memory is also
+  // also released, future accesses to those histograms will seg-fault.
+  CHECK(!g_allocator);
+  g_allocator = allocator.release();
+  size_t existing = StatisticsRecorder::GetHistogramCount();
+
+  DVLOG_IF(1, existing)
+      << existing << " histograms were created before persistence was enabled.";
+}
+
+// static
+GlobalHistogramAllocator* GlobalHistogramAllocator::Get() {
+  return g_allocator;
+}
+
+// static
+std::unique_ptr<GlobalHistogramAllocator>
+GlobalHistogramAllocator::ReleaseForTesting() {
+  GlobalHistogramAllocator* histogram_allocator = g_allocator;
+  if (!histogram_allocator)
+    return nullptr;
+  PersistentMemoryAllocator* memory_allocator =
+      histogram_allocator->memory_allocator();
+
+  // Before releasing the memory, it's necessary to have the Statistics-
+  // Recorder forget about the histograms contained therein; otherwise,
+  // some operations will try to access them and the released memory.
+  PersistentMemoryAllocator::Iterator iter(memory_allocator);
+  PersistentMemoryAllocator::Reference ref;
+  while ((ref = iter.GetNextOfType(kTypeIdHistogram)) != 0) {
+    PersistentHistogramData* histogram_data =
+        memory_allocator->GetAsObject<PersistentHistogramData>(
+            ref, kTypeIdHistogram);
+    DCHECK(histogram_data);
+    StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name);
+
+    // If a test breaks here then a memory region containing a histogram
+    // actively used by this code is being released back to the test.
+    // If that memory segment were to be deleted, future calls to create
+    // persistent histograms would crash. To avoid this, have the test call
+    // the method GetCreateHistogramResultHistogram() *before* setting
+    // the (temporary) memory allocator via SetGlobalAllocator() so that
+    // histogram is instead allocated from the process heap.
+    DCHECK_NE(kResultHistogram, histogram_data->name);
+  }
+
+  g_allocator = nullptr;
+  return WrapUnique(histogram_allocator);
+};
+
+void GlobalHistogramAllocator::SetPersistentLocation(const FilePath& location) {
+  persistent_location_ = location;
+}
+
+const FilePath& GlobalHistogramAllocator::GetPersistentLocation() const {
+  return persistent_location_;
+}
+
+bool GlobalHistogramAllocator::WriteToPersistentLocation() {
+#if defined(OS_NACL)
+  // NACL doesn't support file operations, including ImportantFileWriter.
+  NOTREACHED();
+  return false;
+#else
+  // Stop if no destination is set.
+  if (persistent_location_.empty()) {
+    NOTREACHED() << "Could not write \"" << Name() << "\" persistent histograms"
+                 << " to file because no location was set.";
+    return false;
+  }
+
+  StringPiece contents(static_cast<const char*>(data()), used());
+  if (!ImportantFileWriter::WriteFileAtomically(persistent_location_,
+                                                contents)) {
+    LOG(ERROR) << "Could not write \"" << Name() << "\" persistent histograms"
+               << " to file: " << persistent_location_.value();
+    return false;
+  }
+
+  return true;
+#endif
+}
+
+GlobalHistogramAllocator::GlobalHistogramAllocator(
+    std::unique_ptr<PersistentMemoryAllocator> memory)
+    : PersistentHistogramAllocator(std::move(memory)),
+      import_iterator_(this) {}
+
+void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() {
+  // Skip the import if it's the histogram that was last created. Should a
+  // race condition cause the "last created" to be overwritten before it
+  // is recognized here then the histogram will be created and be ignored
+  // when it is detected as a duplicate by the statistics-recorder. This
+  // simple check reduces the time of creating persistent histograms by
+  // about 40%.
+  Reference record_to_ignore = last_created();
+
+  // There is no lock on this because the iterator is lock-free while still
+  // guaranteed to only return each entry only once. The StatisticsRecorder
+  // has its own lock so the Register operation is safe.
+  while (true) {
+    std::unique_ptr<HistogramBase> histogram =
+        import_iterator_.GetNextWithIgnore(record_to_ignore);
+    if (!histogram)
+      break;
+    StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release());
+  }
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/persistent_histogram_allocator.h b/libchrome/base/metrics/persistent_histogram_allocator.h
new file mode 100644
index 0000000..ee1fba5
--- /dev/null
+++ b/libchrome/base/metrics/persistent_histogram_allocator.h
@@ -0,0 +1,479 @@
+// Copyright 2016 The Chromium Authors. All 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_PERSISTENCE_H_
+#define BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
+
+#include <map>
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/feature_list.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class FilePath;
+class PersistentSampleMapRecords;
+class PersistentSparseHistogramDataManager;
+
+// Feature definition for enabling histogram persistence.
+BASE_EXPORT extern const Feature kPersistentHistogramsFeature;
+
+
+// A data manager for sparse histograms so each instance of such doesn't have
+// to separately iterate over the entire memory segment. Though this class
+// will generally be accessed through the PersistentHistogramAllocator above,
+// it can be used independently on any PersistentMemoryAllocator (making it
+// useable for testing). This object supports only one instance of a sparse
+// histogram for a given id. Tests that create multiple identical histograms,
+// perhaps to simulate multiple processes, should create a separate manager
+// for each.
+class BASE_EXPORT PersistentSparseHistogramDataManager {
+ public:
+  // Constructs the data manager. The allocator must live longer than any
+  // managers that reference it.
+  explicit PersistentSparseHistogramDataManager(
+      PersistentMemoryAllocator* allocator);
+
+  ~PersistentSparseHistogramDataManager();
+
+  // Returns the object that manages the persistent-sample-map records for a
+  // given |id|. Only one |user| of this data is allowed at a time. This does
+  // an automatic Acquire() on the records. The user must call Release() on
+  // the returned object when it is finished with it. Ownership of the records
+  // object stays with this manager.
+  PersistentSampleMapRecords* UseSampleMapRecords(uint64_t id,
+                                                  const void* user);
+
+  // Convenience method that gets the object for a given reference so callers
+  // don't have to also keep their own pointer to the appropriate allocator.
+  template <typename T>
+  T* GetAsObject(PersistentMemoryAllocator::Reference ref, uint32_t type_id) {
+    return allocator_->GetAsObject<T>(ref, type_id);
+  }
+
+ private:
+  friend class PersistentSampleMapRecords;
+
+  // Gets the object holding records for a given sample-map id when |lock_|
+  // has already been acquired.
+  PersistentSampleMapRecords* GetSampleMapRecordsWhileLocked(uint64_t id);
+
+  // Loads sample-map records looking for those belonging to the specified
+  // |load_id|. Records found for other sample-maps are held for later use
+  // without having to iterate again. This should be called only from a
+  // PersistentSampleMapRecords object because those objects have a contract
+  // that there are no other threads accessing the internal records_ field
+  // of the object that is passed in.
+  bool LoadRecords(PersistentSampleMapRecords* sample_map_records);
+
+  // Weak-pointer to the allocator used by the sparse histograms.
+  PersistentMemoryAllocator* allocator_;
+
+  // Iterator within the allocator for finding sample records.
+  PersistentMemoryAllocator::Iterator record_iterator_;
+
+  // Mapping of sample-map IDs to their sample records.
+  std::map<uint64_t, std::unique_ptr<PersistentSampleMapRecords>>
+      sample_records_;
+
+  // A lock used for synchronizing changes to sample_records_.
+  base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(PersistentSparseHistogramDataManager);
+};
+
+
+// This class manages sample-records used by a PersistentSampleMap container
+// that underlies a persistent SparseHistogram object. It is broken out into a
+// top-level class so that it can be forward-declared in other header files
+// rather than include this entire file as would be necessary if it were
+// declared within the PersistentSparseHistogramDataManager class above.
+class BASE_EXPORT PersistentSampleMapRecords {
+ public:
+  // Constructs an instance of this class. The manager object must live longer
+  // than all instances of this class that reference it, which is not usually
+  // a problem since these objects are generally managed from within that
+  // manager instance.
+  PersistentSampleMapRecords(PersistentSparseHistogramDataManager* data_manager,
+                             uint64_t sample_map_id);
+
+  ~PersistentSampleMapRecords();
+
+  // Resets the internal state for a new object using this data. The return
+  // value is "this" as a convenience.
+  PersistentSampleMapRecords* Acquire(const void* user);
+
+  // Indicates that the using object is done with this data.
+  void Release(const void* user);
+
+  // Gets the next reference to a persistent sample-map record. The type and
+  // layout of the data being referenced is defined entirely within the
+  // PersistentSampleMap class.
+  PersistentMemoryAllocator::Reference GetNext();
+
+  // Creates a new persistent sample-map record for sample |value| and returns
+  // a reference to it.
+  PersistentMemoryAllocator::Reference CreateNew(HistogramBase::Sample value);
+
+  // Convenience method that gets the object for a given reference so callers
+  // don't have to also keep their own pointer to the appropriate allocator.
+  // This is expected to be used with the SampleRecord structure defined inside
+  // the persistent_sample_map.cc file but since that isn't exported (for
+  // cleanliness of the interface), a template is defined that will be
+  // resolved when used inside that file.
+  template <typename T>
+  T* GetAsObject(PersistentMemoryAllocator::Reference ref, uint32_t type_id) {
+    return data_manager_->GetAsObject<T>(ref, type_id);
+  }
+
+ private:
+  friend PersistentSparseHistogramDataManager;
+
+  // Weak-pointer to the parent data-manager object.
+  PersistentSparseHistogramDataManager* data_manager_;
+
+  // ID of PersistentSampleMap to which these records apply.
+  const uint64_t sample_map_id_;
+
+  // The current user of this set of records. It is used to ensure that no
+  // more than one object is using these records at a given time.
+  const void* user_ = nullptr;
+
+  // This is the count of how many "records" have already been read by the
+  // owning sample-map.
+  size_t seen_ = 0;
+
+  // This is the set of records previously found for a sample map. Because
+  // there is ever only one object with a given ID (typically a hash of a
+  // histogram name) and because the parent SparseHistogram has acquired
+  // its own lock before accessing the PersistentSampleMap it controls, this
+  // list can be accessed without acquiring any additional lock.
+  std::vector<PersistentMemoryAllocator::Reference> records_;
+
+  // This is the set of records found during iteration through memory. It
+  // is appended in bulk to "records". Access to this vector can be done
+  // only while holding the parent manager's lock.
+  std::vector<PersistentMemoryAllocator::Reference> found_;
+
+  DISALLOW_COPY_AND_ASSIGN(PersistentSampleMapRecords);
+};
+
+
+// This class manages histograms created within a PersistentMemoryAllocator.
+class BASE_EXPORT PersistentHistogramAllocator {
+ public:
+  // A reference to a histogram. While this is implemented as PMA::Reference,
+  // it is not conceptually the same thing. Outside callers should always use
+  // a Reference matching the class it is for and not mix the two.
+  using Reference = PersistentMemoryAllocator::Reference;
+
+  // Iterator used for fetching persistent histograms from an allocator.
+  // It is lock-free and thread-safe.
+  // See PersistentMemoryAllocator::Iterator for more information.
+  class BASE_EXPORT Iterator {
+   public:
+    // Constructs an iterator on a given |allocator|, starting at the beginning.
+    // The allocator must live beyond the lifetime of the iterator.
+    explicit Iterator(PersistentHistogramAllocator* allocator);
+
+    // Gets the next histogram from persistent memory; returns null if there
+    // are no more histograms to be found. This may still be called again
+    // later to retrieve any new histograms added in the meantime.
+    std::unique_ptr<HistogramBase> GetNext() { return GetNextWithIgnore(0); }
+
+    // Gets the next histogram from persistent memory, ignoring one particular
+    // reference in the process. Pass |ignore| of zero (0) to ignore nothing.
+    std::unique_ptr<HistogramBase> GetNextWithIgnore(Reference ignore);
+
+   private:
+    // Weak-pointer to histogram allocator being iterated over.
+    PersistentHistogramAllocator* allocator_;
+
+    // The iterator used for stepping through objects in persistent memory.
+    // It is lock-free and thread-safe which is why this class is also such.
+    PersistentMemoryAllocator::Iterator memory_iter_;
+
+    DISALLOW_COPY_AND_ASSIGN(Iterator);
+  };
+
+  // A PersistentHistogramAllocator is constructed from a PersistentMemory-
+  // Allocator object of which it takes ownership.
+  explicit PersistentHistogramAllocator(
+      std::unique_ptr<PersistentMemoryAllocator> memory);
+  virtual ~PersistentHistogramAllocator();
+
+  // Direct access to underlying memory allocator. If the segment is shared
+  // across threads or processes, reading data through these values does
+  // not guarantee consistency. Use with care. Do not write.
+  PersistentMemoryAllocator* memory_allocator() {
+    return memory_allocator_.get();
+  }
+
+  // Implement the "metadata" API of a PersistentMemoryAllocator, forwarding
+  // those requests to the real one.
+  uint64_t Id() const { return memory_allocator_->Id(); }
+  const char* Name() const { return memory_allocator_->Name(); }
+  const void* data() const { return memory_allocator_->data(); }
+  size_t length() const { return memory_allocator_->length(); }
+  size_t size() const { return memory_allocator_->size(); }
+  size_t used() const { return memory_allocator_->used(); }
+
+  // Recreate a Histogram from data held in persistent memory. Though this
+  // object will be local to the current process, the sample data will be
+  // shared with all other threads referencing it. This method takes a |ref|
+  // to where the top-level histogram data may be found in this allocator.
+  // This method will return null if any problem is detected with the data.
+  std::unique_ptr<HistogramBase> GetHistogram(Reference ref);
+
+  // Allocate a new persistent histogram. The returned histogram will not
+  // be able to be located by other allocators until it is "finalized".
+  std::unique_ptr<HistogramBase> AllocateHistogram(
+      HistogramType histogram_type,
+      const std::string& name,
+      int minimum,
+      int maximum,
+      const BucketRanges* bucket_ranges,
+      int32_t flags,
+      Reference* ref_ptr);
+
+  // Finalize the creation of the histogram, making it available to other
+  // processes if |registered| (as in: added to the StatisticsRecorder) is
+  // True, forgetting it otherwise.
+  void FinalizeHistogram(Reference ref, bool registered);
+
+  // Merges the data in a persistent histogram with one held globally by the
+  // StatisticsRecorder, updating the "logged" samples within the passed
+  // object so that repeated merges are allowed. Don't call this on a "global"
+  // allocator because histograms created there will already be in the SR.
+  void MergeHistogramDeltaToStatisticsRecorder(HistogramBase* histogram);
+
+  // As above but merge the "final" delta. No update of "logged" samples is
+  // done which means it can operate on read-only objects. It's essential,
+  // however, not to call this more than once or those final samples will
+  // get recorded again.
+  void MergeHistogramFinalDeltaToStatisticsRecorder(
+      const HistogramBase* histogram);
+
+  // Returns the object that manages the persistent-sample-map records for a
+  // given |id|. Only one |user| of this data is allowed at a time. This does
+  // an automatic Acquire() on the records. The user must call Release() on
+  // the returned object when it is finished with it. Ownership stays with
+  // this allocator.
+  PersistentSampleMapRecords* UseSampleMapRecords(uint64_t id,
+                                                  const void* user);
+
+  // Create internal histograms for tracking memory use and allocation sizes
+  // for allocator of |name| (which can simply be the result of Name()). This
+  // is done seperately from construction for situations such as when the
+  // histograms will be backed by memory provided by this very allocator.
+  //
+  // IMPORTANT: Callers must update tools/metrics/histograms/histograms.xml
+  // with the following histograms:
+  //    UMA.PersistentAllocator.name.Allocs
+  //    UMA.PersistentAllocator.name.UsedPct
+  void CreateTrackingHistograms(StringPiece name);
+  void UpdateTrackingHistograms();
+
+  // Clears the internal |last_created_| reference so testing can validate
+  // operation without that optimization.
+  void ClearLastCreatedReferenceForTesting();
+
+  // Histogram containing creation results. Visible for testing.
+  static HistogramBase* GetCreateHistogramResultHistogram();
+
+ protected:
+  // The structure used to hold histogram data in persistent memory. It is
+  // defined and used entirely within the .cc file.
+  struct PersistentHistogramData;
+
+  // Gets the reference of the last histogram created, used to avoid
+  // trying to import what was just created.
+  PersistentHistogramAllocator::Reference last_created() {
+    return subtle::NoBarrier_Load(&last_created_);
+  }
+
+  // Gets the next histogram in persistent data based on iterator while
+  // ignoring a particular reference if it is found.
+  std::unique_ptr<HistogramBase> GetNextHistogramWithIgnore(Iterator* iter,
+                                                            Reference ignore);
+
+ private:
+  // Enumerate possible creation results for reporting.
+  enum CreateHistogramResultType {
+    // Everything was fine.
+    CREATE_HISTOGRAM_SUCCESS = 0,
+
+    // Pointer to metadata was not valid.
+    CREATE_HISTOGRAM_INVALID_METADATA_POINTER,
+
+    // Histogram metadata was not valid.
+    CREATE_HISTOGRAM_INVALID_METADATA,
+
+    // Ranges information was not valid.
+    CREATE_HISTOGRAM_INVALID_RANGES_ARRAY,
+
+    // Counts information was not valid.
+    CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY,
+
+    // Could not allocate histogram memory due to corruption.
+    CREATE_HISTOGRAM_ALLOCATOR_CORRUPT,
+
+    // Could not allocate histogram memory due to lack of space.
+    CREATE_HISTOGRAM_ALLOCATOR_FULL,
+
+    // Could not allocate histogram memory due to unknown error.
+    CREATE_HISTOGRAM_ALLOCATOR_ERROR,
+
+    // Histogram was of unknown type.
+    CREATE_HISTOGRAM_UNKNOWN_TYPE,
+
+    // Instance has detected a corrupt allocator (recorded only once).
+    CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT,
+
+    // Always keep this at the end.
+    CREATE_HISTOGRAM_MAX
+  };
+
+  // Create a histogram based on saved (persistent) information about it.
+  std::unique_ptr<HistogramBase> CreateHistogram(
+      PersistentHistogramData* histogram_data_ptr);
+
+  // Gets or creates an object in the global StatisticsRecorder matching
+  // the |histogram| passed. Null is returned if one was not found and
+  // one could not be created.
+  HistogramBase* GetOrCreateStatisticsRecorderHistogram(
+      const HistogramBase* histogram);
+
+  // Record the result of a histogram creation.
+  static void RecordCreateHistogramResult(CreateHistogramResultType result);
+
+  // The memory allocator that provides the actual histogram storage.
+  std::unique_ptr<PersistentMemoryAllocator> memory_allocator_;
+
+  // The data-manager used to improve performance of sparse histograms.
+  PersistentSparseHistogramDataManager sparse_histogram_data_manager_;
+
+  // A reference to the last-created histogram in the allocator, used to avoid
+  // trying to import what was just created.
+  // TODO(bcwhite): Change this to std::atomic<PMA::Reference> when available.
+  subtle::Atomic32 last_created_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocator);
+};
+
+
+// A special case of the PersistentHistogramAllocator that operates on a
+// global scale, collecting histograms created through standard macros and
+// the FactoryGet() method.
+class BASE_EXPORT GlobalHistogramAllocator
+    : public PersistentHistogramAllocator {
+ public:
+  ~GlobalHistogramAllocator() override;
+
+  // Create a global allocator using the passed-in memory |base|, |size|, and
+  // other parameters. Ownership of the memory segment remains with the caller.
+  static void CreateWithPersistentMemory(void* base,
+                                         size_t size,
+                                         size_t page_size,
+                                         uint64_t id,
+                                         StringPiece name);
+
+  // Create a global allocator using an internal block of memory of the
+  // specified |size| taken from the heap.
+  static void CreateWithLocalMemory(size_t size, uint64_t id, StringPiece name);
+
+#if !defined(OS_NACL)
+  // Create a global allocator by memory-mapping a |file|. If the file does
+  // not exist, it will be created with the specified |size|. If the file does
+  // exist, the allocator will use and add to its contents, ignoring the passed
+  // size in favor of the existing size.
+  static void CreateWithFile(const FilePath& file_path,
+                             size_t size,
+                             uint64_t id,
+                             StringPiece name);
+#endif
+
+  // Create a global allocator using a block of shared |memory| of the
+  // specified |size|. The allocator takes ownership of the shared memory
+  // and releases it upon destruction, though the memory will continue to
+  // live if other processes have access to it.
+  static void CreateWithSharedMemory(std::unique_ptr<SharedMemory> memory,
+                                     size_t size,
+                                     uint64_t id,
+                                     StringPiece name);
+
+  // Create a global allocator using a block of shared memory accessed
+  // through the given |handle| and |size|. The allocator takes ownership
+  // of the handle and closes it upon destruction, though the memory will
+  // continue to live if other processes have access to it.
+  static void CreateWithSharedMemoryHandle(const SharedMemoryHandle& handle,
+                                           size_t size);
+
+  // Sets a GlobalHistogramAllocator for globally storing histograms in
+  // a space that can be persisted or shared between processes. There is only
+  // ever one allocator for all such histograms created by a single process.
+  // This takes ownership of the object and should be called as soon as
+  // possible during startup to capture as many histograms as possible and
+  // while operating single-threaded so there are no race-conditions.
+  static void Set(std::unique_ptr<GlobalHistogramAllocator> allocator);
+
+  // Gets a pointer to the global histogram allocator. Returns null if none
+  // exists.
+  static GlobalHistogramAllocator* Get();
+
+  // This access to the persistent allocator is only for testing; it extracts
+  // the current allocator completely. This allows easy creation of histograms
+  // within persistent memory segments which can then be extracted and used in
+  // other ways.
+  static std::unique_ptr<GlobalHistogramAllocator> ReleaseForTesting();
+
+  // Stores a pathname to which the contents of this allocator should be saved
+  // in order to persist the data for a later use.
+  void SetPersistentLocation(const FilePath& location);
+
+  // Retrieves a previously set pathname to which the contents of this allocator
+  // are to be saved.
+  const FilePath& GetPersistentLocation() const;
+
+  // Writes the internal data to a previously set location. This is generally
+  // called when a process is exiting from a section of code that may not know
+  // the filesystem. The data is written in an atomic manner. The return value
+  // indicates success.
+  bool WriteToPersistentLocation();
+
+ private:
+  friend class StatisticsRecorder;
+
+  // Creates a new global histogram allocator.
+  explicit GlobalHistogramAllocator(
+      std::unique_ptr<PersistentMemoryAllocator> memory);
+
+  // Import new histograms from the global histogram allocator. It's possible
+  // for other processes to create histograms in the active memory segment;
+  // this adds those to the internal list of known histograms to avoid creating
+  // duplicates that would have to be merged during reporting. Every call to
+  // this method resumes from the last entry it saw; it costs nothing if
+  // nothing new has been added.
+  void ImportHistogramsToStatisticsRecorder();
+
+  // Import always continues from where it left off, making use of a single
+  // iterator to continue the work.
+  Iterator import_iterator_;
+
+  // The location to which the data should be persisted.
+  FilePath persistent_location_;
+
+  DISALLOW_COPY_AND_ASSIGN(GlobalHistogramAllocator);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
diff --git a/libchrome/base/metrics/persistent_histogram_allocator_unittest.cc b/libchrome/base/metrics/persistent_histogram_allocator_unittest.cc
new file mode 100644
index 0000000..b680662
--- /dev/null
+++ b/libchrome/base/metrics/persistent_histogram_allocator_unittest.cc
@@ -0,0 +1,209 @@
+// Copyright 2016 The Chromium Authors. All 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/persistent_histogram_allocator.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/metrics/statistics_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class PersistentHistogramAllocatorTest : public testing::Test {
+ protected:
+  const int32_t kAllocatorMemorySize = 64 << 10;  // 64 KiB
+
+  PersistentHistogramAllocatorTest()
+      : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()) {
+    CreatePersistentHistogramAllocator();
+  }
+  ~PersistentHistogramAllocatorTest() override {
+    DestroyPersistentHistogramAllocator();
+  }
+
+  void CreatePersistentHistogramAllocator() {
+    allocator_memory_.reset(new char[kAllocatorMemorySize]);
+
+    GlobalHistogramAllocator::ReleaseForTesting();
+    memset(allocator_memory_.get(), 0, kAllocatorMemorySize);
+    GlobalHistogramAllocator::GetCreateHistogramResultHistogram();
+    GlobalHistogramAllocator::CreateWithPersistentMemory(
+        allocator_memory_.get(), kAllocatorMemorySize, 0, 0,
+        "PersistentHistogramAllocatorTest");
+    allocator_ = GlobalHistogramAllocator::Get()->memory_allocator();
+  }
+
+  void DestroyPersistentHistogramAllocator() {
+    allocator_ = nullptr;
+    GlobalHistogramAllocator::ReleaseForTesting();
+  }
+
+  std::unique_ptr<StatisticsRecorder> statistics_recorder_;
+  std::unique_ptr<char[]> allocator_memory_;
+  PersistentMemoryAllocator* allocator_ = nullptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocatorTest);
+};
+
+TEST_F(PersistentHistogramAllocatorTest, CreateAndIterateTest) {
+  PersistentMemoryAllocator::MemoryInfo meminfo0;
+  allocator_->GetMemoryInfo(&meminfo0);
+
+  // Try basic construction
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
+  EXPECT_TRUE(histogram);
+  histogram->CheckName("TestHistogram");
+  PersistentMemoryAllocator::MemoryInfo meminfo1;
+  allocator_->GetMemoryInfo(&meminfo1);
+  EXPECT_GT(meminfo0.free, meminfo1.free);
+
+  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
+  EXPECT_TRUE(linear_histogram);
+  linear_histogram->CheckName("TestLinearHistogram");
+  PersistentMemoryAllocator::MemoryInfo meminfo2;
+  allocator_->GetMemoryInfo(&meminfo2);
+  EXPECT_GT(meminfo1.free, meminfo2.free);
+
+  HistogramBase* boolean_histogram = BooleanHistogram::FactoryGet(
+      "TestBooleanHistogram", HistogramBase::kIsPersistent);
+  EXPECT_TRUE(boolean_histogram);
+  boolean_histogram->CheckName("TestBooleanHistogram");
+  PersistentMemoryAllocator::MemoryInfo meminfo3;
+  allocator_->GetMemoryInfo(&meminfo3);
+  EXPECT_GT(meminfo2.free, meminfo3.free);
+
+  std::vector<int> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(5);
+  HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, HistogramBase::kIsPersistent);
+  EXPECT_TRUE(custom_histogram);
+  custom_histogram->CheckName("TestCustomHistogram");
+  PersistentMemoryAllocator::MemoryInfo meminfo4;
+  allocator_->GetMemoryInfo(&meminfo4);
+  EXPECT_GT(meminfo3.free, meminfo4.free);
+
+  PersistentMemoryAllocator::Iterator iter(allocator_);
+  uint32_t type;
+  EXPECT_NE(0U, iter.GetNext(&type));  // Histogram
+  EXPECT_NE(0U, iter.GetNext(&type));  // LinearHistogram
+  EXPECT_NE(0U, iter.GetNext(&type));  // BooleanHistogram
+  EXPECT_NE(0U, iter.GetNext(&type));  // CustomHistogram
+  EXPECT_EQ(0U, iter.GetNext(&type));
+
+  // Create a second allocator and have it access the memory of the first.
+  std::unique_ptr<HistogramBase> recovered;
+  PersistentHistogramAllocator recovery(
+      WrapUnique(new PersistentMemoryAllocator(
+          allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false)));
+  PersistentHistogramAllocator::Iterator histogram_iter(&recovery);
+
+  recovered = histogram_iter.GetNext();
+  ASSERT_TRUE(recovered);
+  recovered->CheckName("TestHistogram");
+
+  recovered = histogram_iter.GetNext();
+  ASSERT_TRUE(recovered);
+  recovered->CheckName("TestLinearHistogram");
+
+  recovered = histogram_iter.GetNext();
+  ASSERT_TRUE(recovered);
+  recovered->CheckName("TestBooleanHistogram");
+
+  recovered = histogram_iter.GetNext();
+  ASSERT_TRUE(recovered);
+  recovered->CheckName("TestCustomHistogram");
+
+  recovered = histogram_iter.GetNext();
+  EXPECT_FALSE(recovered);
+}
+
+TEST_F(PersistentHistogramAllocatorTest, CreateWithFileTest) {
+  const char temp_name[] = "CreateWithFileTest";
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath temp_file = temp_dir.path().AppendASCII(temp_name);
+  const size_t temp_size = 64 << 10;  // 64 KiB
+
+  // Test creation of a new file.
+  GlobalHistogramAllocator::ReleaseForTesting();
+  GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, temp_name);
+  EXPECT_EQ(std::string(temp_name),
+            GlobalHistogramAllocator::Get()->memory_allocator()->Name());
+
+  // Test re-open of a possibly-existing file.
+  GlobalHistogramAllocator::ReleaseForTesting();
+  GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, "");
+  EXPECT_EQ(std::string(temp_name),
+            GlobalHistogramAllocator::Get()->memory_allocator()->Name());
+
+  // Test re-open of an known-existing file.
+  GlobalHistogramAllocator::ReleaseForTesting();
+  GlobalHistogramAllocator::CreateWithFile(temp_file, 0, 0, "");
+  EXPECT_EQ(std::string(temp_name),
+            GlobalHistogramAllocator::Get()->memory_allocator()->Name());
+
+  // Final release so file and temp-dir can be removed.
+  GlobalHistogramAllocator::ReleaseForTesting();
+}
+
+TEST_F(PersistentHistogramAllocatorTest, StatisticsRecorderTest) {
+  size_t starting_sr_count = StatisticsRecorder::GetHistogramCount();
+
+  // Create a local StatisticsRecorder in which the newly created histogram
+  // will be recorded.
+  std::unique_ptr<StatisticsRecorder> local_sr =
+      StatisticsRecorder::CreateTemporaryForTesting();
+  EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount());
+
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      "TestHistogram", 1, 10, 10, HistogramBase::kIsPersistent);
+  EXPECT_TRUE(histogram);
+  EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount());
+  histogram->Add(3);
+  histogram->Add(1);
+  histogram->Add(4);
+  histogram->Add(1);
+  histogram->Add(6);
+
+  // Destroy the local SR and ensure that we're back to the initial state.
+  local_sr.reset();
+  EXPECT_EQ(starting_sr_count, StatisticsRecorder::GetHistogramCount());
+
+  // Create a second allocator and have it access the memory of the first.
+  std::unique_ptr<HistogramBase> recovered;
+  PersistentHistogramAllocator recovery(
+      WrapUnique(new PersistentMemoryAllocator(
+          allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false)));
+  PersistentHistogramAllocator::Iterator histogram_iter(&recovery);
+
+  recovered = histogram_iter.GetNext();
+  ASSERT_TRUE(recovered);
+
+  // Merge the recovered histogram to the SR. It will always be a new object.
+  recovery.MergeHistogramDeltaToStatisticsRecorder(recovered.get());
+  EXPECT_EQ(starting_sr_count + 1, StatisticsRecorder::GetHistogramCount());
+  HistogramBase* found =
+      StatisticsRecorder::FindHistogram(recovered->histogram_name());
+  ASSERT_TRUE(found);
+  EXPECT_NE(recovered.get(), found);
+
+  // Ensure that the data got merged, too.
+  std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples();
+  EXPECT_EQ(recovered->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
+  EXPECT_EQ(1, snapshot->GetCount(3));
+  EXPECT_EQ(2, snapshot->GetCount(1));
+  EXPECT_EQ(1, snapshot->GetCount(4));
+  EXPECT_EQ(1, snapshot->GetCount(6));
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/persistent_memory_allocator.cc b/libchrome/base/metrics/persistent_memory_allocator.cc
new file mode 100644
index 0000000..dfa408f
--- /dev/null
+++ b/libchrome/base/metrics/persistent_memory_allocator.cc
@@ -0,0 +1,830 @@
+// 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/metrics/persistent_memory_allocator.h"
+
+#include <assert.h>
+#include <algorithm>
+
+#if defined(OS_WIN)
+#include "winbase.h"
+#elif defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
+
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/histogram_macros.h"
+
+namespace {
+
+// Limit of memory segment size. It has to fit in an unsigned 32-bit number
+// and should be a power of 2 in order to accomodate almost any page size.
+const uint32_t kSegmentMaxSize = 1 << 30;  // 1 GiB
+
+// A constant (random) value placed in the shared metadata to identify
+// an already initialized memory segment.
+const uint32_t kGlobalCookie = 0x408305DC;
+
+// The current version of the metadata. If updates are made that change
+// the metadata, the version number can be queried to operate in a backward-
+// compatible manner until the memory segment is completely re-initalized.
+const uint32_t kGlobalVersion = 1;
+
+// Constant values placed in the block headers to indicate its state.
+const uint32_t kBlockCookieFree = 0;
+const uint32_t kBlockCookieQueue = 1;
+const uint32_t kBlockCookieWasted = (uint32_t)-1;
+const uint32_t kBlockCookieAllocated = 0xC8799269;
+
+// TODO(bcwhite): When acceptable, consider moving flags to std::atomic<char>
+// types rather than combined bitfield.
+
+// Flags stored in the flags_ field of the SharedMetaData structure below.
+enum : int {
+  kFlagCorrupt = 1 << 0,
+  kFlagFull    = 1 << 1
+};
+
+bool CheckFlag(const volatile std::atomic<uint32_t>* flags, int flag) {
+  uint32_t loaded_flags = flags->load(std::memory_order_relaxed);
+  return (loaded_flags & flag) != 0;
+}
+
+void SetFlag(volatile std::atomic<uint32_t>* flags, int flag) {
+  uint32_t loaded_flags = flags->load(std::memory_order_relaxed);
+  for (;;) {
+    uint32_t new_flags = (loaded_flags & ~flag) | flag;
+    // In the failue case, actual "flags" value stored in loaded_flags.
+    if (flags->compare_exchange_weak(loaded_flags, new_flags))
+      break;
+  }
+}
+
+}  // namespace
+
+namespace base {
+
+// All allocations and data-structures must be aligned to this byte boundary.
+// Alignment as large as the physical bus between CPU and RAM is _required_
+// for some architectures, is simply more efficient on other CPUs, and
+// generally a Good Idea(tm) for all platforms as it reduces/eliminates the
+// chance that a type will span cache lines. Alignment mustn't be less
+// than 8 to ensure proper alignment for all types. The rest is a balance
+// between reducing spans across multiple cache lines and wasted space spent
+// padding out allocations. An alignment of 16 would ensure that the block
+// header structure always sits in a single cache line. An average of about
+// 1/2 this value will be wasted with every allocation.
+const uint32_t PersistentMemoryAllocator::kAllocAlignment = 8;
+
+// The block-header is placed at the top of every allocation within the
+// segment to describe the data that follows it.
+struct PersistentMemoryAllocator::BlockHeader {
+  uint32_t size;       // Number of bytes in this block, including header.
+  uint32_t cookie;     // Constant value indicating completed allocation.
+  std::atomic<uint32_t> type_id;  // Arbitrary number indicating data type.
+  std::atomic<uint32_t> next;     // Pointer to the next block when iterating.
+};
+
+// The shared metadata exists once at the top of the memory segment to
+// describe the state of the allocator to all processes.
+struct PersistentMemoryAllocator::SharedMetadata {
+  uint32_t cookie;     // Some value that indicates complete initialization.
+  uint32_t size;       // Total size of memory segment.
+  uint32_t page_size;  // Paging size within memory segment.
+  uint32_t version;    // Version code so upgrades don't break.
+  uint64_t id;         // Arbitrary ID number given by creator.
+  uint32_t name;       // Reference to stored name string.
+
+  // Above is read-only after first construction. Below may be changed and
+  // so must be marked "volatile" to provide correct inter-process behavior.
+
+  // Bitfield of information flags. Access to this should be done through
+  // the CheckFlag() and SetFlag() methods defined above.
+  volatile std::atomic<uint32_t> flags;
+
+  // Offset/reference to first free space in segment.
+  volatile std::atomic<uint32_t> freeptr;
+
+  // The "iterable" queue is an M&S Queue as described here, append-only:
+  // https://www.research.ibm.com/people/m/michael/podc-1996.pdf
+  volatile std::atomic<uint32_t> tailptr;  // Last block of iteration queue.
+  volatile BlockHeader queue;   // Empty block for linked-list head/tail.
+};
+
+// The "queue" block header is used to detect "last node" so that zero/null
+// can be used to indicate that it hasn't been added at all. It is part of
+// the SharedMetadata structure which itself is always located at offset zero.
+const PersistentMemoryAllocator::Reference
+    PersistentMemoryAllocator::kReferenceQueue =
+        offsetof(SharedMetadata, queue);
+
+const base::FilePath::CharType PersistentMemoryAllocator::kFileExtension[] =
+    FILE_PATH_LITERAL(".pma");
+
+
+PersistentMemoryAllocator::Iterator::Iterator(
+    const PersistentMemoryAllocator* allocator)
+    : allocator_(allocator), last_record_(kReferenceQueue), record_count_(0) {}
+
+PersistentMemoryAllocator::Iterator::Iterator(
+    const PersistentMemoryAllocator* allocator,
+    Reference starting_after)
+    : allocator_(allocator), last_record_(starting_after), record_count_(0) {
+  // Ensure that the starting point is a valid, iterable block (meaning it can
+  // be read and has a non-zero "next" pointer).
+  const volatile BlockHeader* block =
+      allocator_->GetBlock(starting_after, 0, 0, false, false);
+  if (!block || block->next.load(std::memory_order_relaxed) == 0) {
+    NOTREACHED();
+    last_record_.store(kReferenceQueue, std::memory_order_release);
+  }
+}
+
+PersistentMemoryAllocator::Reference
+PersistentMemoryAllocator::Iterator::GetNext(uint32_t* type_return) {
+  // Make a copy of the existing count of found-records, acquiring all changes
+  // made to the allocator, notably "freeptr" (see comment in loop for why
+  // the load of that value cannot be moved above here) that occurred during
+  // any previous runs of this method, including those by parallel threads
+  // that interrupted it. It pairs with the Release at the end of this method.
+  //
+  // Otherwise, if the compiler were to arrange the two loads such that
+  // "count" was fetched _after_ "freeptr" then it would be possible for
+  // this thread to be interrupted between them and other threads perform
+  // multiple allocations, make-iterables, and iterations (with the included
+  // increment of |record_count_|) culminating in the check at the bottom
+  // mistakenly determining that a loop exists. Isn't this stuff fun?
+  uint32_t count = record_count_.load(std::memory_order_acquire);
+
+  Reference last = last_record_.load(std::memory_order_acquire);
+  Reference next;
+  while (true) {
+    const volatile BlockHeader* block =
+        allocator_->GetBlock(last, 0, 0, true, false);
+    if (!block)  // Invalid iterator state.
+      return kReferenceNull;
+
+    // The compiler and CPU can freely reorder all memory accesses on which
+    // there are no dependencies. It could, for example, move the load of
+    // "freeptr" to above this point because there are no explicit dependencies
+    // between it and "next". If it did, however, then another block could
+    // be queued after that but before the following load meaning there is
+    // one more queued block than the future "detect loop by having more
+    // blocks that could fit before freeptr" will allow.
+    //
+    // By "acquiring" the "next" value here, it's synchronized to the enqueue
+    // of the node which in turn is synchronized to the allocation (which sets
+    // freeptr). Thus, the scenario above cannot happen.
+    next = block->next.load(std::memory_order_acquire);
+    if (next == kReferenceQueue)  // No next allocation in queue.
+      return kReferenceNull;
+    block = allocator_->GetBlock(next, 0, 0, false, false);
+    if (!block) {  // Memory is corrupt.
+      allocator_->SetCorrupt();
+      return kReferenceNull;
+    }
+
+    // Update the "last_record" pointer to be the reference being returned.
+    // If it fails then another thread has already iterated past it so loop
+    // again. Failing will also load the existing value into "last" so there
+    // is no need to do another such load when the while-loop restarts. A
+    // "strong" compare-exchange is used because failing unnecessarily would
+    // mean repeating some fairly costly validations above.
+    if (last_record_.compare_exchange_strong(last, next)) {
+      *type_return = block->type_id.load(std::memory_order_relaxed);
+      break;
+    }
+  }
+
+  // Memory corruption could cause a loop in the list. Such must be detected
+  // so as to not cause an infinite loop in the caller. This is done by simply
+  // making sure it doesn't iterate more times than the absolute maximum
+  // number of allocations that could have been made. Callers are likely
+  // to loop multiple times before it is detected but at least it stops.
+  const uint32_t freeptr = std::min(
+      allocator_->shared_meta()->freeptr.load(std::memory_order_relaxed),
+      allocator_->mem_size_);
+  const uint32_t max_records =
+      freeptr / (sizeof(BlockHeader) + kAllocAlignment);
+  if (count > max_records) {
+    allocator_->SetCorrupt();
+    return kReferenceNull;
+  }
+
+  // Increment the count and release the changes made above. It pairs with
+  // the Acquire at the top of this method. Note that this operation is not
+  // strictly synchonized with fetching of the object to return, which would
+  // have to be done inside the loop and is somewhat complicated to achieve.
+  // It does not matter if it falls behind temporarily so long as it never
+  // gets ahead.
+  record_count_.fetch_add(1, std::memory_order_release);
+  return next;
+}
+
+PersistentMemoryAllocator::Reference
+PersistentMemoryAllocator::Iterator::GetNextOfType(uint32_t type_match) {
+  Reference ref;
+  uint32_t type_found;
+  while ((ref = GetNext(&type_found)) != 0) {
+    if (type_found == type_match)
+      return ref;
+  }
+  return kReferenceNull;
+}
+
+
+// static
+bool PersistentMemoryAllocator::IsMemoryAcceptable(const void* base,
+                                                   size_t size,
+                                                   size_t page_size,
+                                                   bool readonly) {
+  return ((base && reinterpret_cast<uintptr_t>(base) % kAllocAlignment == 0) &&
+          (size >= sizeof(SharedMetadata) && size <= kSegmentMaxSize) &&
+          (size % kAllocAlignment == 0 || readonly) &&
+          (page_size == 0 || size % page_size == 0 || readonly));
+}
+
+PersistentMemoryAllocator::PersistentMemoryAllocator(
+    void* base,
+    size_t size,
+    size_t page_size,
+    uint64_t id,
+    base::StringPiece name,
+    bool readonly)
+    : mem_base_(static_cast<char*>(base)),
+      mem_size_(static_cast<uint32_t>(size)),
+      mem_page_(static_cast<uint32_t>((page_size ? page_size : size))),
+      readonly_(readonly),
+      corrupt_(0),
+      allocs_histogram_(nullptr),
+      used_histogram_(nullptr) {
+  static_assert(sizeof(BlockHeader) % kAllocAlignment == 0,
+                "BlockHeader is not a multiple of kAllocAlignment");
+  static_assert(sizeof(SharedMetadata) % kAllocAlignment == 0,
+                "SharedMetadata is not a multiple of kAllocAlignment");
+  static_assert(kReferenceQueue % kAllocAlignment == 0,
+                "\"queue\" is not aligned properly; must be at end of struct");
+
+  // Ensure that memory segment is of acceptable size.
+  CHECK(IsMemoryAcceptable(base, size, page_size, readonly));
+
+  // These atomics operate inter-process and so must be lock-free. The local
+  // casts are to make sure it can be evaluated at compile time to a constant.
+  CHECK(((SharedMetadata*)0)->freeptr.is_lock_free());
+  CHECK(((SharedMetadata*)0)->flags.is_lock_free());
+  CHECK(((BlockHeader*)0)->next.is_lock_free());
+  CHECK(corrupt_.is_lock_free());
+
+  if (shared_meta()->cookie != kGlobalCookie) {
+    if (readonly) {
+      SetCorrupt();
+      return;
+    }
+
+    // This block is only executed when a completely new memory segment is
+    // being initialized. It's unshared and single-threaded...
+    volatile BlockHeader* const first_block =
+        reinterpret_cast<volatile BlockHeader*>(mem_base_ +
+                                                sizeof(SharedMetadata));
+    if (shared_meta()->cookie != 0 ||
+        shared_meta()->size != 0 ||
+        shared_meta()->version != 0 ||
+        shared_meta()->freeptr.load(std::memory_order_relaxed) != 0 ||
+        shared_meta()->flags.load(std::memory_order_relaxed) != 0 ||
+        shared_meta()->id != 0 ||
+        shared_meta()->name != 0 ||
+        shared_meta()->tailptr != 0 ||
+        shared_meta()->queue.cookie != 0 ||
+        shared_meta()->queue.next.load(std::memory_order_relaxed) != 0 ||
+        first_block->size != 0 ||
+        first_block->cookie != 0 ||
+        first_block->type_id.load(std::memory_order_relaxed) != 0 ||
+        first_block->next != 0) {
+      // ...or something malicious has been playing with the metadata.
+      SetCorrupt();
+    }
+
+    // This is still safe to do even if corruption has been detected.
+    shared_meta()->cookie = kGlobalCookie;
+    shared_meta()->size = mem_size_;
+    shared_meta()->page_size = mem_page_;
+    shared_meta()->version = kGlobalVersion;
+    shared_meta()->id = id;
+    shared_meta()->freeptr.store(sizeof(SharedMetadata),
+                                 std::memory_order_release);
+
+    // Set up the queue of iterable allocations.
+    shared_meta()->queue.size = sizeof(BlockHeader);
+    shared_meta()->queue.cookie = kBlockCookieQueue;
+    shared_meta()->queue.next.store(kReferenceQueue, std::memory_order_release);
+    shared_meta()->tailptr.store(kReferenceQueue, std::memory_order_release);
+
+    // Allocate space for the name so other processes can learn it.
+    if (!name.empty()) {
+      const size_t name_length = name.length() + 1;
+      shared_meta()->name = Allocate(name_length, 0);
+      char* name_cstr = GetAsObject<char>(shared_meta()->name, 0);
+      if (name_cstr)
+        memcpy(name_cstr, name.data(), name.length());
+    }
+  } else {
+    if (shared_meta()->size == 0 ||
+        shared_meta()->version == 0 ||
+        shared_meta()->freeptr.load(std::memory_order_relaxed) == 0 ||
+        shared_meta()->tailptr == 0 ||
+        shared_meta()->queue.cookie == 0 ||
+        shared_meta()->queue.next.load(std::memory_order_relaxed) == 0) {
+      SetCorrupt();
+    }
+    if (!readonly) {
+      // The allocator is attaching to a previously initialized segment of
+      // memory. If the initialization parameters differ, make the best of it
+      // by reducing the local construction parameters to match those of
+      // the actual memory area. This ensures that the local object never
+      // tries to write outside of the original bounds.
+      // Because the fields are const to ensure that no code other than the
+      // constructor makes changes to them as well as to give optimization
+      // hints to the compiler, it's necessary to const-cast them for changes
+      // here.
+      if (shared_meta()->size < mem_size_)
+        *const_cast<uint32_t*>(&mem_size_) = shared_meta()->size;
+      if (shared_meta()->page_size < mem_page_)
+        *const_cast<uint32_t*>(&mem_page_) = shared_meta()->page_size;
+
+      // Ensure that settings are still valid after the above adjustments.
+      if (!IsMemoryAcceptable(base, mem_size_, mem_page_, readonly))
+        SetCorrupt();
+    }
+  }
+}
+
+PersistentMemoryAllocator::~PersistentMemoryAllocator() {
+  // It's strictly forbidden to do any memory access here in case there is
+  // some issue with the underlying memory segment. The "Local" allocator
+  // makes use of this to allow deletion of the segment on the heap from
+  // within its destructor.
+}
+
+uint64_t PersistentMemoryAllocator::Id() const {
+  return shared_meta()->id;
+}
+
+const char* PersistentMemoryAllocator::Name() const {
+  Reference name_ref = shared_meta()->name;
+  const char* name_cstr = GetAsObject<char>(name_ref, 0);
+  if (!name_cstr)
+    return "";
+
+  size_t name_length = GetAllocSize(name_ref);
+  if (name_cstr[name_length - 1] != '\0') {
+    NOTREACHED();
+    SetCorrupt();
+    return "";
+  }
+
+  return name_cstr;
+}
+
+void PersistentMemoryAllocator::CreateTrackingHistograms(
+    base::StringPiece name) {
+  if (name.empty() || readonly_)
+    return;
+
+  std::string name_string = name.as_string();
+  DCHECK(!used_histogram_);
+  used_histogram_ = LinearHistogram::FactoryGet(
+      "UMA.PersistentAllocator." + name_string + ".UsedPct", 1, 101, 21,
+      HistogramBase::kUmaTargetedHistogramFlag);
+
+  DCHECK(!allocs_histogram_);
+  allocs_histogram_ = Histogram::FactoryGet(
+      "UMA.PersistentAllocator." + name_string + ".Allocs", 1, 10000, 50,
+      HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+size_t PersistentMemoryAllocator::used() const {
+  return std::min(shared_meta()->freeptr.load(std::memory_order_relaxed),
+                  mem_size_);
+}
+
+size_t PersistentMemoryAllocator::GetAllocSize(Reference ref) const {
+  const volatile BlockHeader* const block = GetBlock(ref, 0, 0, false, false);
+  if (!block)
+    return 0;
+  uint32_t size = block->size;
+  // Header was verified by GetBlock() but a malicious actor could change
+  // the value between there and here. Check it again.
+  if (size <= sizeof(BlockHeader) || ref + size > mem_size_) {
+    SetCorrupt();
+    return 0;
+  }
+  return size - sizeof(BlockHeader);
+}
+
+uint32_t PersistentMemoryAllocator::GetType(Reference ref) const {
+  const volatile BlockHeader* const block = GetBlock(ref, 0, 0, false, false);
+  if (!block)
+    return 0;
+  return block->type_id.load(std::memory_order_relaxed);
+}
+
+bool PersistentMemoryAllocator::ChangeType(Reference ref,
+                                           uint32_t to_type_id,
+                                           uint32_t from_type_id) {
+  DCHECK(!readonly_);
+  volatile BlockHeader* const block = GetBlock(ref, 0, 0, false, false);
+  if (!block)
+    return false;
+
+  // This is a "strong" exchange because there is no loop that can retry in
+  // the wake of spurious failures possible with "weak" exchanges.
+  return block->type_id.compare_exchange_strong(from_type_id, to_type_id);
+}
+
+PersistentMemoryAllocator::Reference PersistentMemoryAllocator::Allocate(
+    size_t req_size,
+    uint32_t type_id) {
+  Reference ref = AllocateImpl(req_size, type_id);
+  if (ref) {
+    // Success: Record this allocation in usage stats (if active).
+    if (allocs_histogram_)
+      allocs_histogram_->Add(static_cast<HistogramBase::Sample>(req_size));
+  } else {
+    // Failure: Record an allocation of zero for tracking.
+    if (allocs_histogram_)
+      allocs_histogram_->Add(0);
+  }
+  return ref;
+}
+
+PersistentMemoryAllocator::Reference PersistentMemoryAllocator::AllocateImpl(
+    size_t req_size,
+    uint32_t type_id) {
+  DCHECK(!readonly_);
+
+  // Validate req_size to ensure it won't overflow when used as 32-bit value.
+  if (req_size > kSegmentMaxSize - sizeof(BlockHeader)) {
+    NOTREACHED();
+    return kReferenceNull;
+  }
+
+  // Round up the requested size, plus header, to the next allocation alignment.
+  uint32_t size = static_cast<uint32_t>(req_size + sizeof(BlockHeader));
+  size = (size + (kAllocAlignment - 1)) & ~(kAllocAlignment - 1);
+  if (size <= sizeof(BlockHeader) || size > mem_page_) {
+    NOTREACHED();
+    return kReferenceNull;
+  }
+
+  // Get the current start of unallocated memory. Other threads may
+  // update this at any time and cause us to retry these operations.
+  // This value should be treated as "const" to avoid confusion through
+  // the code below but recognize that any failed compare-exchange operation
+  // involving it will cause it to be loaded with a more recent value. The
+  // code should either exit or restart the loop in that case.
+  /* const */ uint32_t freeptr =
+      shared_meta()->freeptr.load(std::memory_order_acquire);
+
+  // Allocation is lockless so we do all our caculation and then, if saving
+  // indicates a change has occurred since we started, scrap everything and
+  // start over.
+  for (;;) {
+    if (IsCorrupt())
+      return kReferenceNull;
+
+    if (freeptr + size > mem_size_) {
+      SetFlag(&shared_meta()->flags, kFlagFull);
+      return kReferenceNull;
+    }
+
+    // Get pointer to the "free" block. If something has been allocated since
+    // the load of freeptr above, it is still safe as nothing will be written
+    // to that location until after the compare-exchange below.
+    volatile BlockHeader* const block = GetBlock(freeptr, 0, 0, false, true);
+    if (!block) {
+      SetCorrupt();
+      return kReferenceNull;
+    }
+
+    // An allocation cannot cross page boundaries. If it would, create a
+    // "wasted" block and begin again at the top of the next page. This
+    // area could just be left empty but we fill in the block header just
+    // for completeness sake.
+    const uint32_t page_free = mem_page_ - freeptr % mem_page_;
+    if (size > page_free) {
+      if (page_free <= sizeof(BlockHeader)) {
+        SetCorrupt();
+        return kReferenceNull;
+      }
+      const uint32_t new_freeptr = freeptr + page_free;
+      if (shared_meta()->freeptr.compare_exchange_strong(freeptr,
+                                                         new_freeptr)) {
+        block->size = page_free;
+        block->cookie = kBlockCookieWasted;
+      }
+      continue;
+    }
+
+    // Don't leave a slice at the end of a page too small for anything. This
+    // can result in an allocation up to two alignment-sizes greater than the
+    // minimum required by requested-size + header + alignment.
+    if (page_free - size < sizeof(BlockHeader) + kAllocAlignment)
+      size = page_free;
+
+    const uint32_t new_freeptr = freeptr + size;
+    if (new_freeptr > mem_size_) {
+      SetCorrupt();
+      return kReferenceNull;
+    }
+
+    // Save our work. Try again if another thread has completed an allocation
+    // while we were processing. A "weak" exchange would be permissable here
+    // because the code will just loop and try again but the above processing
+    // is significant so make the extra effort of a "strong" exchange.
+    if (!shared_meta()->freeptr.compare_exchange_strong(freeptr, new_freeptr))
+      continue;
+
+    // Given that all memory was zeroed before ever being given to an instance
+    // of this class and given that we only allocate in a monotomic fashion
+    // going forward, it must be that the newly allocated block is completely
+    // full of zeros. If we find anything in the block header that is NOT a
+    // zero then something must have previously run amuck through memory,
+    // writing beyond the allocated space and into unallocated space.
+    if (block->size != 0 ||
+        block->cookie != kBlockCookieFree ||
+        block->type_id.load(std::memory_order_relaxed) != 0 ||
+        block->next.load(std::memory_order_relaxed) != 0) {
+      SetCorrupt();
+      return kReferenceNull;
+    }
+
+    block->size = size;
+    block->cookie = kBlockCookieAllocated;
+    block->type_id.store(type_id, std::memory_order_relaxed);
+    return freeptr;
+  }
+}
+
+void PersistentMemoryAllocator::GetMemoryInfo(MemoryInfo* meminfo) const {
+  uint32_t remaining = std::max(
+      mem_size_ - shared_meta()->freeptr.load(std::memory_order_relaxed),
+      (uint32_t)sizeof(BlockHeader));
+  meminfo->total = mem_size_;
+  meminfo->free = IsCorrupt() ? 0 : remaining - sizeof(BlockHeader);
+}
+
+void PersistentMemoryAllocator::MakeIterable(Reference ref) {
+  DCHECK(!readonly_);
+  if (IsCorrupt())
+    return;
+  volatile BlockHeader* block = GetBlock(ref, 0, 0, false, false);
+  if (!block)  // invalid reference
+    return;
+  if (block->next.load(std::memory_order_acquire) != 0)  // Already iterable.
+    return;
+  block->next.store(kReferenceQueue, std::memory_order_release);  // New tail.
+
+  // Try to add this block to the tail of the queue. May take multiple tries.
+  // If so, tail will be automatically updated with a more recent value during
+  // compare-exchange operations.
+  uint32_t tail = shared_meta()->tailptr.load(std::memory_order_acquire);
+  for (;;) {
+    // Acquire the current tail-pointer released by previous call to this
+    // method and validate it.
+    block = GetBlock(tail, 0, 0, true, false);
+    if (!block) {
+      SetCorrupt();
+      return;
+    }
+
+    // Try to insert the block at the tail of the queue. The tail node always
+    // has an existing value of kReferenceQueue; if that is somehow not the
+    // existing value then another thread has acted in the meantime. A "strong"
+    // exchange is necessary so the "else" block does not get executed when
+    // that is not actually the case (which can happen with a "weak" exchange).
+    uint32_t next = kReferenceQueue;  // Will get replaced with existing value.
+    if (block->next.compare_exchange_strong(next, ref,
+                                            std::memory_order_acq_rel,
+                                            std::memory_order_acquire)) {
+      // Update the tail pointer to the new offset. If the "else" clause did
+      // not exist, then this could be a simple Release_Store to set the new
+      // value but because it does, it's possible that other threads could add
+      // one or more nodes at the tail before reaching this point. We don't
+      // have to check the return value because it either operates correctly
+      // or the exact same operation has already been done (by the "else"
+      // clause) on some other thread.
+      shared_meta()->tailptr.compare_exchange_strong(tail, ref,
+                                                     std::memory_order_release,
+                                                     std::memory_order_relaxed);
+      return;
+    } else {
+      // In the unlikely case that a thread crashed or was killed between the
+      // update of "next" and the update of "tailptr", it is necessary to
+      // perform the operation that would have been done. There's no explicit
+      // check for crash/kill which means that this operation may also happen
+      // even when the other thread is in perfect working order which is what
+      // necessitates the CompareAndSwap above.
+      shared_meta()->tailptr.compare_exchange_strong(tail, next,
+                                                     std::memory_order_acq_rel,
+                                                     std::memory_order_acquire);
+    }
+  }
+}
+
+// The "corrupted" state is held both locally and globally (shared). The
+// shared flag can't be trusted since a malicious actor could overwrite it.
+// Because corruption can be detected during read-only operations such as
+// iteration, this method may be called by other "const" methods. In this
+// case, it's safe to discard the constness and modify the local flag and
+// maybe even the shared flag if the underlying data isn't actually read-only.
+void PersistentMemoryAllocator::SetCorrupt() const {
+  LOG(ERROR) << "Corruption detected in shared-memory segment.";
+  const_cast<std::atomic<bool>*>(&corrupt_)->store(true,
+                                                   std::memory_order_relaxed);
+  if (!readonly_) {
+    SetFlag(const_cast<volatile std::atomic<uint32_t>*>(&shared_meta()->flags),
+            kFlagCorrupt);
+  }
+}
+
+bool PersistentMemoryAllocator::IsCorrupt() const {
+  if (corrupt_.load(std::memory_order_relaxed) ||
+      CheckFlag(&shared_meta()->flags, kFlagCorrupt)) {
+    SetCorrupt();  // Make sure all indicators are set.
+    return true;
+  }
+  return false;
+}
+
+bool PersistentMemoryAllocator::IsFull() const {
+  return CheckFlag(&shared_meta()->flags, kFlagFull);
+}
+
+// Dereference a block |ref| and ensure that it's valid for the desired
+// |type_id| and |size|. |special| indicates that we may try to access block
+// headers not available to callers but still accessed by this module. By
+// having internal dereferences go through this same function, the allocator
+// is hardened against corruption.
+const volatile PersistentMemoryAllocator::BlockHeader*
+PersistentMemoryAllocator::GetBlock(Reference ref, uint32_t type_id,
+                                    uint32_t size, bool queue_ok,
+                                    bool free_ok) const {
+  // Validation of parameters.
+  if (ref % kAllocAlignment != 0)
+    return nullptr;
+  if (ref < (queue_ok ? kReferenceQueue : sizeof(SharedMetadata)))
+    return nullptr;
+  size += sizeof(BlockHeader);
+  if (ref + size > mem_size_)
+    return nullptr;
+
+  // Validation of referenced block-header.
+  if (!free_ok) {
+    uint32_t freeptr = std::min(
+        shared_meta()->freeptr.load(std::memory_order_relaxed), mem_size_);
+    if (ref + size > freeptr)
+      return nullptr;
+    const volatile BlockHeader* const block =
+        reinterpret_cast<volatile BlockHeader*>(mem_base_ + ref);
+    if (block->size < size)
+      return nullptr;
+    if (ref + block->size > freeptr)
+      return nullptr;
+    if (ref != kReferenceQueue && block->cookie != kBlockCookieAllocated)
+      return nullptr;
+    if (type_id != 0 &&
+        block->type_id.load(std::memory_order_relaxed) != type_id) {
+      return nullptr;
+    }
+  }
+
+  // Return pointer to block data.
+  return reinterpret_cast<const volatile BlockHeader*>(mem_base_ + ref);
+}
+
+const volatile void* PersistentMemoryAllocator::GetBlockData(
+    Reference ref,
+    uint32_t type_id,
+    uint32_t size) const {
+  DCHECK(size > 0);
+  const volatile BlockHeader* block =
+      GetBlock(ref, type_id, size, false, false);
+  if (!block)
+    return nullptr;
+  return reinterpret_cast<const volatile char*>(block) + sizeof(BlockHeader);
+}
+
+void PersistentMemoryAllocator::UpdateTrackingHistograms() {
+  DCHECK(!readonly_);
+  if (used_histogram_) {
+    MemoryInfo meminfo;
+    GetMemoryInfo(&meminfo);
+    HistogramBase::Sample used_percent = static_cast<HistogramBase::Sample>(
+        ((meminfo.total - meminfo.free) * 100ULL / meminfo.total));
+    used_histogram_->Add(used_percent);
+  }
+}
+
+
+//----- LocalPersistentMemoryAllocator -----------------------------------------
+
+LocalPersistentMemoryAllocator::LocalPersistentMemoryAllocator(
+    size_t size,
+    uint64_t id,
+    base::StringPiece name)
+    : PersistentMemoryAllocator(AllocateLocalMemory(size),
+                                size, 0, id, name, false) {}
+
+LocalPersistentMemoryAllocator::~LocalPersistentMemoryAllocator() {
+  DeallocateLocalMemory(const_cast<char*>(mem_base_), mem_size_);
+}
+
+// static
+void* LocalPersistentMemoryAllocator::AllocateLocalMemory(size_t size) {
+#if defined(OS_WIN)
+  void* address =
+      ::VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+  DPCHECK(address);
+  return address;
+#elif defined(OS_POSIX)
+  // MAP_ANON is deprecated on Linux but MAP_ANONYMOUS is not universal on Mac.
+  // MAP_SHARED is not available on Linux <2.4 but required on Mac.
+  void* address = ::mmap(nullptr, size, PROT_READ | PROT_WRITE,
+                         MAP_ANON | MAP_SHARED, -1, 0);
+  DPCHECK(MAP_FAILED != address);
+  return address;
+#else
+#error This architecture is not (yet) supported.
+#endif
+}
+
+// static
+void LocalPersistentMemoryAllocator::DeallocateLocalMemory(void* memory,
+                                                           size_t size) {
+#if defined(OS_WIN)
+  BOOL success = ::VirtualFree(memory, 0, MEM_DECOMMIT);
+  DPCHECK(success);
+#elif defined(OS_POSIX)
+  int result = ::munmap(memory, size);
+  DPCHECK(0 == result);
+#else
+#error This architecture is not (yet) supported.
+#endif
+}
+
+
+//----- SharedPersistentMemoryAllocator ----------------------------------------
+
+SharedPersistentMemoryAllocator::SharedPersistentMemoryAllocator(
+    std::unique_ptr<SharedMemory> memory,
+    uint64_t id,
+    base::StringPiece name,
+    bool read_only)
+    : PersistentMemoryAllocator(static_cast<uint8_t*>(memory->memory()),
+                                memory->mapped_size(),
+                                0,
+                                id,
+                                name,
+                                read_only),
+      shared_memory_(std::move(memory)) {}
+
+SharedPersistentMemoryAllocator::~SharedPersistentMemoryAllocator() {}
+
+// static
+bool SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(
+    const SharedMemory& memory) {
+  return IsMemoryAcceptable(memory.memory(), memory.mapped_size(), 0, false);
+}
+
+
+#if !defined(OS_NACL)
+//----- FilePersistentMemoryAllocator ------------------------------------------
+
+FilePersistentMemoryAllocator::FilePersistentMemoryAllocator(
+    std::unique_ptr<MemoryMappedFile> file,
+    size_t max_size,
+    uint64_t id,
+    base::StringPiece name,
+    bool read_only)
+    : PersistentMemoryAllocator(const_cast<uint8_t*>(file->data()),
+                                max_size != 0 ? max_size : file->length(),
+                                0,
+                                id,
+                                name,
+                                read_only),
+      mapped_file_(std::move(file)) {}
+
+FilePersistentMemoryAllocator::~FilePersistentMemoryAllocator() {}
+
+// static
+bool FilePersistentMemoryAllocator::IsFileAcceptable(
+    const MemoryMappedFile& file,
+    bool read_only) {
+  return IsMemoryAcceptable(file.data(), file.length(), 0, read_only);
+}
+#endif  // !defined(OS_NACL)
+
+}  // namespace base
diff --git a/libchrome/base/metrics/persistent_memory_allocator.h b/libchrome/base/metrics/persistent_memory_allocator.h
new file mode 100644
index 0000000..2fc0d2d
--- /dev/null
+++ b/libchrome/base/metrics/persistent_memory_allocator.h
@@ -0,0 +1,429 @@
+// 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_METRICS_PERSISTENT_MEMORY_ALLOCATOR_H_
+#define BASE_METRICS_PERSISTENT_MEMORY_ALLOCATOR_H_
+
+#include <stdint.h>
+
+#include <atomic>
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+class HistogramBase;
+class MemoryMappedFile;
+class SharedMemory;
+
+// Simple allocator for pieces of a memory block that may be persistent
+// to some storage or shared across multiple processes. This class resides
+// under base/metrics because it was written for that purpose. It is,
+// however, fully general-purpose and can be freely moved to base/memory
+// if other uses are found.
+//
+// This class provides for thread-secure (i.e. safe against other threads
+// or processes that may be compromised and thus have malicious intent)
+// allocation of memory within a designated block and also a mechanism by
+// which other threads can learn of these allocations.
+//
+// There is (currently) no way to release an allocated block of data because
+// doing so would risk invalidating pointers held by other processes and
+// greatly complicate the allocation algorithm.
+//
+// Construction of this object can accept new, clean (i.e. zeroed) memory
+// or previously initialized memory. In the first case, construction must
+// be allowed to complete before letting other allocators attach to the same
+// segment. In other words, don't share the segment until at least one
+// allocator has been attached to it.
+//
+// Note that memory not in active use is not accessed so it is possible to
+// use virtual memory, including memory-mapped files, as backing storage with
+// the OS "pinning" new (zeroed) physical RAM pages only as they are needed.
+class BASE_EXPORT PersistentMemoryAllocator {
+ public:
+  typedef uint32_t Reference;
+
+  // Iterator for going through all iterable memory records in an allocator.
+  // Like the allocator itself, iterators are lock-free and thread-secure.
+  // That means that multiple threads can share an iterator and the same
+  // reference will not be returned twice.
+  //
+  // Iteration, in general, is tolerant of corrupted memory. It will return
+  // what it can and stop only when corruption forces it to. Bad corruption
+  // could cause the same object to be returned many times but it will
+  // eventually quit.
+  class BASE_EXPORT Iterator {
+   public:
+    // Constructs an iterator on a given |allocator|, starting at the beginning.
+    // The allocator must live beyond the lifetime of the iterator. This class
+    // has read-only access to the allocator (hence "const") but the returned
+    // references can be used on a read/write version, too.
+    explicit Iterator(const PersistentMemoryAllocator* allocator);
+
+    // As above but resuming from the |starting_after| reference. The first call
+    // to GetNext() will return the next object found after that reference. The
+    // reference must be to an "iterable" object; references to non-iterable
+    // objects (those that never had MakeIterable() called for them) will cause
+    // a run-time error.
+    Iterator(const PersistentMemoryAllocator* allocator,
+             Reference starting_after);
+
+    // Gets the next iterable, storing that type in |type_return|. The actual
+    // return value is a reference to the allocation inside the allocator or
+    // zero if there are no more. GetNext() may still be called again at a
+    // later time to retrieve any new allocations that have been added.
+    Reference GetNext(uint32_t* type_return);
+
+    // Similar to above but gets the next iterable of a specific |type_match|.
+    // This should not be mixed with calls to GetNext() because any allocations
+    // skipped here due to a type mis-match will never be returned by later
+    // calls to GetNext() meaning it's possible to completely miss entries.
+    Reference GetNextOfType(uint32_t type_match);
+
+    // Converts references to objects. This is a convenience method so that
+    // users of the iterator don't need to also have their own pointer to the
+    // allocator over which the iterator runs in order to retrieve objects.
+    // Because the iterator is not read/write, only "const" objects can be
+    // fetched. Non-const objects can be fetched using the reference on a
+    // non-const (external) pointer to the same allocator (or use const_cast
+    // to remove the qualifier).
+    template <typename T>
+    const T* GetAsObject(Reference ref, uint32_t type_id) const {
+      return allocator_->GetAsObject<T>(ref, type_id);
+    }
+
+   private:
+    // Weak-pointer to memory allocator being iterated over.
+    const PersistentMemoryAllocator* allocator_;
+
+    // The last record that was returned.
+    std::atomic<Reference> last_record_;
+
+    // The number of records found; used for detecting loops.
+    std::atomic<uint32_t> record_count_;
+
+    DISALLOW_COPY_AND_ASSIGN(Iterator);
+  };
+
+  // Returned information about the internal state of the heap.
+  struct MemoryInfo {
+    size_t total;
+    size_t free;
+  };
+
+  enum : Reference {
+    kReferenceNull = 0  // A common "null" reference value.
+  };
+
+  enum : uint32_t {
+    kTypeIdAny = 0  // Match any type-id inside GetAsObject().
+  };
+
+  // This is the standard file extension (suitable for being passed to the
+  // AddExtension() method of base::FilePath) for dumps of persistent memory.
+  static const base::FilePath::CharType kFileExtension[];
+
+  // The allocator operates on any arbitrary block of memory. Creation and
+  // persisting or sharing of that block with another process is the
+  // responsibility of the caller. The allocator needs to know only the
+  // block's |base| address, the total |size| of the block, and any internal
+  // |page| size (zero if not paged) across which allocations should not span.
+  // The |id| is an arbitrary value the caller can use to identify a
+  // particular memory segment. It will only be loaded during the initial
+  // creation of the segment and can be checked by the caller for consistency.
+  // The |name|, if provided, is used to distinguish histograms for this
+  // allocator. Only the primary owner of the segment should define this value;
+  // other processes can learn it from the shared state. If the underlying
+  // memory is |readonly| then no changes will be made to it. The resulting
+  // object should be stored as a "const" pointer.
+  //
+  // PersistentMemoryAllocator does NOT take ownership of the memory block.
+  // The caller must manage it and ensure it stays available throughout the
+  // lifetime of this object.
+  //
+  // Memory segments for sharing must have had an allocator attached to them
+  // before actually being shared. If the memory segment was just created, it
+  // should be zeroed before being passed here. If it was an existing segment,
+  // the values here will be compared to copies stored in the shared segment
+  // as a guard against corruption.
+  //
+  // Make sure that the memory segment is acceptable (see IsMemoryAcceptable()
+  // method below) before construction if the definition of the segment can
+  // vary in any way at run-time. Invalid memory segments will cause a crash.
+  PersistentMemoryAllocator(void* base, size_t size, size_t page_size,
+                            uint64_t id, base::StringPiece name,
+                            bool readonly);
+  virtual ~PersistentMemoryAllocator();
+
+  // Check if memory segment is acceptable for creation of an Allocator. This
+  // doesn't do any analysis of the data and so doesn't guarantee that the
+  // contents are valid, just that the paramaters won't cause the program to
+  // abort. The IsCorrupt() method will report detection of data problems
+  // found during construction and general operation.
+  static bool IsMemoryAcceptable(const void* data, size_t size,
+                                 size_t page_size, bool readonly);
+
+  // Get the internal identifier for this persistent memory segment.
+  uint64_t Id() const;
+
+  // Get the internal name of this allocator (possibly an empty string).
+  const char* Name() const;
+
+  // Is this segment open only for read?
+  bool IsReadonly() { return readonly_; }
+
+  // Create internal histograms for tracking memory use and allocation sizes
+  // for allocator of |name| (which can simply be the result of Name()). This
+  // is done seperately from construction for situations such as when the
+  // histograms will be backed by memory provided by this very allocator.
+  //
+  // IMPORTANT: Callers must update tools/metrics/histograms/histograms.xml
+  // with the following histograms:
+  //    UMA.PersistentAllocator.name.Allocs
+  //    UMA.PersistentAllocator.name.UsedPct
+  void CreateTrackingHistograms(base::StringPiece name);
+
+  // Direct access to underlying memory segment. If the segment is shared
+  // across threads or processes, reading data through these values does
+  // not guarantee consistency. Use with care. Do not write.
+  const void* data() const { return const_cast<const char*>(mem_base_); }
+  size_t length() const { return mem_size_; }
+  size_t size() const { return mem_size_; }
+  size_t used() const;
+
+  // Get an object referenced by a |ref|. For safety reasons, the |type_id|
+  // code and size-of(|T|) are compared to ensure the reference is valid
+  // and cannot return an object outside of the memory segment. A |type_id| of
+  // kTypeIdAny (zero) will match any though the size is still checked. NULL is
+  // returned if any problem is detected, such as corrupted storage or incorrect
+  // parameters. Callers MUST check that the returned value is not-null EVERY
+  // TIME before accessing it or risk crashing! Once dereferenced, the pointer
+  // is safe to reuse forever.
+  //
+  // NOTE: Though this method will guarantee that an object of the specified
+  // type can be accessed without going outside the bounds of the memory
+  // segment, it makes no guarantees of the validity of the data within the
+  // object itself. If it is expected that the contents of the segment could
+  // be compromised with malicious intent, the object must be hardened as well.
+  //
+  // Though the persistent data may be "volatile" if it is shared with
+  // other processes, such is not necessarily the case. The internal
+  // "volatile" designation is discarded so as to not propagate the viral
+  // nature of that keyword to the caller. It can add it back, if necessary,
+  // based on knowledge of how the allocator is being used.
+  template <typename T>
+  T* GetAsObject(Reference ref, uint32_t type_id) {
+    static_assert(!std::is_polymorphic<T>::value, "no polymorphic objects");
+    return const_cast<T*>(
+        reinterpret_cast<volatile T*>(GetBlockData(ref, type_id, sizeof(T))));
+  }
+  template <typename T>
+  const T* GetAsObject(Reference ref, uint32_t type_id) const {
+    static_assert(!std::is_polymorphic<T>::value, "no polymorphic objects");
+    return const_cast<const T*>(
+        reinterpret_cast<const volatile T*>(GetBlockData(
+            ref, type_id, sizeof(T))));
+  }
+
+  // Get the number of bytes allocated to a block. This is useful when storing
+  // arrays in order to validate the ending boundary. The returned value will
+  // include any padding added to achieve the required alignment and so could
+  // be larger than given in the original Allocate() request.
+  size_t GetAllocSize(Reference ref) const;
+
+  // Access the internal "type" of an object. This generally isn't necessary
+  // but can be used to "clear" the type and so effectively mark it as deleted
+  // even though the memory stays valid and allocated. Changing the type is
+  // an atomic compare/exchange and so requires knowing the existing value.
+  // It will return false if the existing type is not what is expected.
+  uint32_t GetType(Reference ref) const;
+  bool ChangeType(Reference ref, uint32_t to_type_id, uint32_t from_type_id);
+
+  // Reserve space in the memory segment of the desired |size| and |type_id|.
+  // A return value of zero indicates the allocation failed, otherwise the
+  // returned reference can be used by any process to get a real pointer via
+  // the GetAsObject() call.
+  Reference Allocate(size_t size, uint32_t type_id);
+
+  // Allocated objects can be added to an internal list that can then be
+  // iterated over by other processes. If an allocated object can be found
+  // another way, such as by having its reference within a different object
+  // that will be made iterable, then this call is not necessary. This always
+  // succeeds unless corruption is detected; check IsCorrupted() to find out.
+  // Once an object is made iterable, its position in iteration can never
+  // change; new iterable objects will always be added after it in the series.
+  void MakeIterable(Reference ref);
+
+  // Get the information about the amount of free space in the allocator. The
+  // amount of free space should be treated as approximate due to extras from
+  // alignment and metadata. Concurrent allocations from other threads will
+  // also make the true amount less than what is reported.
+  void GetMemoryInfo(MemoryInfo* meminfo) const;
+
+  // If there is some indication that the memory has become corrupted,
+  // calling this will attempt to prevent further damage by indicating to
+  // all processes that something is not as expected.
+  void SetCorrupt() const;
+
+  // This can be called to determine if corruption has been detected in the
+  // segment, possibly my a malicious actor. Once detected, future allocations
+  // will fail and iteration may not locate all objects.
+  bool IsCorrupt() const;
+
+  // Flag set if an allocation has failed because the memory segment was full.
+  bool IsFull() const;
+
+  // Update those "tracking" histograms which do not get updates during regular
+  // operation, such as how much memory is currently used. This should be
+  // called before such information is to be displayed or uploaded.
+  void UpdateTrackingHistograms();
+
+ protected:
+  volatile char* const mem_base_;  // Memory base. (char so sizeof guaranteed 1)
+  const uint32_t mem_size_;        // Size of entire memory segment.
+  const uint32_t mem_page_;        // Page size allocations shouldn't cross.
+
+ private:
+  struct SharedMetadata;
+  struct BlockHeader;
+  static const uint32_t kAllocAlignment;
+  static const Reference kReferenceQueue;
+
+  // The shared metadata is always located at the top of the memory segment.
+  // These convenience functions eliminate constant casting of the base
+  // pointer within the code.
+  const SharedMetadata* shared_meta() const {
+    return reinterpret_cast<const SharedMetadata*>(
+        const_cast<const char*>(mem_base_));
+  }
+  SharedMetadata* shared_meta() {
+    return reinterpret_cast<SharedMetadata*>(const_cast<char*>(mem_base_));
+  }
+
+  // Actual method for doing the allocation.
+  Reference AllocateImpl(size_t size, uint32_t type_id);
+
+  // Get the block header associated with a specific reference.
+  const volatile BlockHeader* GetBlock(Reference ref, uint32_t type_id,
+                                       uint32_t size, bool queue_ok,
+                                       bool free_ok) const;
+  volatile BlockHeader* GetBlock(Reference ref, uint32_t type_id, uint32_t size,
+                                 bool queue_ok, bool free_ok) {
+      return const_cast<volatile BlockHeader*>(
+          const_cast<const PersistentMemoryAllocator*>(this)->GetBlock(
+              ref, type_id, size, queue_ok, free_ok));
+  }
+
+  // Get the actual data within a block associated with a specific reference.
+  const volatile void* GetBlockData(Reference ref, uint32_t type_id,
+                                    uint32_t size) const;
+  volatile void* GetBlockData(Reference ref, uint32_t type_id,
+                              uint32_t size) {
+      return const_cast<volatile void*>(
+          const_cast<const PersistentMemoryAllocator*>(this)->GetBlockData(
+              ref, type_id, size));
+  }
+
+  const bool readonly_;              // Indicates access to read-only memory.
+  std::atomic<bool> corrupt_;        // Local version of "corrupted" flag.
+
+  HistogramBase* allocs_histogram_;  // Histogram recording allocs.
+  HistogramBase* used_histogram_;    // Histogram recording used space.
+
+  friend class PersistentMemoryAllocatorTest;
+  FRIEND_TEST_ALL_PREFIXES(PersistentMemoryAllocatorTest, AllocateAndIterate);
+  DISALLOW_COPY_AND_ASSIGN(PersistentMemoryAllocator);
+};
+
+
+// This allocator uses a local memory block it allocates from the general
+// heap. It is generally used when some kind of "death rattle" handler will
+// save the contents to persistent storage during process shutdown. It is
+// also useful for testing.
+class BASE_EXPORT LocalPersistentMemoryAllocator
+    : public PersistentMemoryAllocator {
+ public:
+  LocalPersistentMemoryAllocator(size_t size, uint64_t id,
+                                 base::StringPiece name);
+  ~LocalPersistentMemoryAllocator() override;
+
+ private:
+  // Allocates a block of local memory of the specified |size|, ensuring that
+  // the memory will not be physically allocated until accessed and will read
+  // as zero when that happens.
+  static void* AllocateLocalMemory(size_t size);
+
+  // Deallocates a block of local |memory| of the specified |size|.
+  static void DeallocateLocalMemory(void* memory, size_t size);
+
+  DISALLOW_COPY_AND_ASSIGN(LocalPersistentMemoryAllocator);
+};
+
+
+// This allocator takes a shared-memory object and performs allocation from
+// it. The memory must be previously mapped via Map() or MapAt(). The allocator
+// takes ownership of the memory object.
+class BASE_EXPORT SharedPersistentMemoryAllocator
+    : public PersistentMemoryAllocator {
+ public:
+  SharedPersistentMemoryAllocator(std::unique_ptr<SharedMemory> memory,
+                                  uint64_t id,
+                                  base::StringPiece name,
+                                  bool read_only);
+  ~SharedPersistentMemoryAllocator() override;
+
+  SharedMemory* shared_memory() { return shared_memory_.get(); }
+
+  // Ensure that the memory isn't so invalid that it won't crash when passing it
+  // to the allocator. This doesn't guarantee the data is valid, just that it
+  // won't cause the program to abort. The existing IsCorrupt() call will handle
+  // the rest.
+  static bool IsSharedMemoryAcceptable(const SharedMemory& memory);
+
+ private:
+  std::unique_ptr<SharedMemory> shared_memory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedPersistentMemoryAllocator);
+};
+
+
+#if !defined(OS_NACL)  // NACL doesn't support any kind of file access in build.
+// This allocator takes a memory-mapped file object and performs allocation
+// from it. The allocator takes ownership of the file object.
+class BASE_EXPORT FilePersistentMemoryAllocator
+    : public PersistentMemoryAllocator {
+ public:
+  // A |max_size| of zero will use the length of the file as the maximum
+  // size. The |file| object must have been already created with sufficient
+  // permissions (read, read/write, or read/write/extend).
+  FilePersistentMemoryAllocator(std::unique_ptr<MemoryMappedFile> file,
+                                size_t max_size,
+                                uint64_t id,
+                                base::StringPiece name,
+                                bool read_only);
+  ~FilePersistentMemoryAllocator() override;
+
+  // Ensure that the file isn't so invalid that it won't crash when passing it
+  // to the allocator. This doesn't guarantee the file is valid, just that it
+  // won't cause the program to abort. The existing IsCorrupt() call will handle
+  // the rest.
+  static bool IsFileAcceptable(const MemoryMappedFile& file, bool read_only);
+
+ private:
+  std::unique_ptr<MemoryMappedFile> mapped_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePersistentMemoryAllocator);
+};
+#endif  // !defined(OS_NACL)
+
+}  // namespace base
+
+#endif  // BASE_METRICS_PERSISTENT_MEMORY_ALLOCATOR_H_
diff --git a/libchrome/base/metrics/persistent_memory_allocator_unittest.cc b/libchrome/base/metrics/persistent_memory_allocator_unittest.cc
new file mode 100644
index 0000000..a3d90c2
--- /dev/null
+++ b/libchrome/base/metrics/persistent_memory_allocator_unittest.cc
@@ -0,0 +1,815 @@
+// 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/persistent_memory_allocator.h"
+
+#include <memory>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/histogram.h"
+#include "base/rand_util.h"
+#include "base/strings/safe_sprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace {
+
+const uint32_t TEST_MEMORY_SIZE = 1 << 20;   // 1 MiB
+const uint32_t TEST_MEMORY_PAGE = 64 << 10;  // 64 KiB
+const uint32_t TEST_ID = 12345;
+const char TEST_NAME[] = "TestAllocator";
+
+}  // namespace
+
+namespace base {
+
+typedef PersistentMemoryAllocator::Reference Reference;
+
+class PersistentMemoryAllocatorTest : public testing::Test {
+ public:
+  // This can't be statically initialized because it's value isn't defined
+  // in the PersistentMemoryAllocator header file. Instead, it's simply set
+  // in the constructor.
+  uint32_t kAllocAlignment;
+
+  struct TestObject1 {
+    int onething;
+    char oranother;
+  };
+
+  struct TestObject2 {
+    int thiis;
+    long that;
+    float andthe;
+    char other;
+    double thing;
+  };
+
+  PersistentMemoryAllocatorTest() {
+    kAllocAlignment = GetAllocAlignment();
+    mem_segment_.reset(new char[TEST_MEMORY_SIZE]);
+  }
+
+  void SetUp() override {
+    allocator_.reset();
+    ::memset(mem_segment_.get(), 0, TEST_MEMORY_SIZE);
+    allocator_.reset(new PersistentMemoryAllocator(
+        mem_segment_.get(), TEST_MEMORY_SIZE, TEST_MEMORY_PAGE,
+        TEST_ID, TEST_NAME, false));
+    allocator_->CreateTrackingHistograms(allocator_->Name());
+  }
+
+  void TearDown() override {
+    allocator_.reset();
+  }
+
+  unsigned CountIterables() {
+    PersistentMemoryAllocator::Iterator iter(allocator_.get());
+    uint32_t type;
+    unsigned count = 0;
+    while (iter.GetNext(&type) != 0) {
+      ++count;
+    }
+    return count;
+  }
+
+  static uint32_t GetAllocAlignment() {
+    return PersistentMemoryAllocator::kAllocAlignment;
+  }
+
+ protected:
+  std::unique_ptr<char[]> mem_segment_;
+  std::unique_ptr<PersistentMemoryAllocator> allocator_;
+};
+
+TEST_F(PersistentMemoryAllocatorTest, AllocateAndIterate) {
+  std::string base_name(TEST_NAME);
+  EXPECT_EQ(TEST_ID, allocator_->Id());
+  EXPECT_TRUE(allocator_->used_histogram_);
+  EXPECT_EQ("UMA.PersistentAllocator." + base_name + ".UsedPct",
+            allocator_->used_histogram_->histogram_name());
+  EXPECT_TRUE(allocator_->allocs_histogram_);
+  EXPECT_EQ("UMA.PersistentAllocator." + base_name + ".Allocs",
+            allocator_->allocs_histogram_->histogram_name());
+
+  // Get base memory info for later comparison.
+  PersistentMemoryAllocator::MemoryInfo meminfo0;
+  allocator_->GetMemoryInfo(&meminfo0);
+  EXPECT_EQ(TEST_MEMORY_SIZE, meminfo0.total);
+  EXPECT_GT(meminfo0.total, meminfo0.free);
+
+  // Validate allocation of test object and make sure it can be referenced
+  // and all metadata looks correct.
+  Reference block1 = allocator_->Allocate(sizeof(TestObject1), 1);
+  EXPECT_NE(0U, block1);
+  EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject1>(block1, 1));
+  EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block1, 1));
+  EXPECT_LE(sizeof(TestObject1), allocator_->GetAllocSize(block1));
+  EXPECT_GT(sizeof(TestObject1) + kAllocAlignment,
+            allocator_->GetAllocSize(block1));
+  PersistentMemoryAllocator::MemoryInfo meminfo1;
+  allocator_->GetMemoryInfo(&meminfo1);
+  EXPECT_EQ(meminfo0.total, meminfo1.total);
+  EXPECT_GT(meminfo0.free, meminfo1.free);
+
+  // Ensure that the test-object can be made iterable.
+  PersistentMemoryAllocator::Iterator iter1a(allocator_.get());
+  uint32_t type;
+  EXPECT_EQ(0U, iter1a.GetNext(&type));
+  allocator_->MakeIterable(block1);
+  EXPECT_EQ(block1, iter1a.GetNext(&type));
+  EXPECT_EQ(1U, type);
+  EXPECT_EQ(0U, iter1a.GetNext(&type));
+
+  // Create second test-object and ensure everything is good and it cannot
+  // be confused with test-object of another type.
+  Reference block2 = allocator_->Allocate(sizeof(TestObject2), 2);
+  EXPECT_NE(0U, block2);
+  EXPECT_NE(nullptr, allocator_->GetAsObject<TestObject2>(block2, 2));
+  EXPECT_EQ(nullptr, allocator_->GetAsObject<TestObject2>(block2, 1));
+  EXPECT_LE(sizeof(TestObject2), allocator_->GetAllocSize(block2));
+  EXPECT_GT(sizeof(TestObject2) + kAllocAlignment,
+            allocator_->GetAllocSize(block2));
+  PersistentMemoryAllocator::MemoryInfo meminfo2;
+  allocator_->GetMemoryInfo(&meminfo2);
+  EXPECT_EQ(meminfo1.total, meminfo2.total);
+  EXPECT_GT(meminfo1.free, meminfo2.free);
+
+  // Ensure that second test-object can also be made iterable.
+  allocator_->MakeIterable(block2);
+  EXPECT_EQ(block2, iter1a.GetNext(&type));
+  EXPECT_EQ(2U, type);
+  EXPECT_EQ(0U, iter1a.GetNext(&type));
+
+  // Check that iteration can begin after an arbitrary location.
+  PersistentMemoryAllocator::Iterator iter1b(allocator_.get(), block1);
+  EXPECT_EQ(block2, iter1b.GetNext(&type));
+  EXPECT_EQ(0U, iter1b.GetNext(&type));
+
+  // Ensure nothing has gone noticably wrong.
+  EXPECT_FALSE(allocator_->IsFull());
+  EXPECT_FALSE(allocator_->IsCorrupt());
+
+  // Check the internal histogram record of used memory.
+  allocator_->UpdateTrackingHistograms();
+  std::unique_ptr<HistogramSamples> used_samples(
+      allocator_->used_histogram_->SnapshotSamples());
+  EXPECT_TRUE(used_samples);
+  EXPECT_EQ(1, used_samples->TotalCount());
+
+  // Check the internal histogram record of allocation requests.
+  std::unique_ptr<HistogramSamples> allocs_samples(
+      allocator_->allocs_histogram_->SnapshotSamples());
+  EXPECT_TRUE(allocs_samples);
+  EXPECT_EQ(2, allocs_samples->TotalCount());
+  EXPECT_EQ(0, allocs_samples->GetCount(0));
+  EXPECT_EQ(1, allocs_samples->GetCount(sizeof(TestObject1)));
+  EXPECT_EQ(1, allocs_samples->GetCount(sizeof(TestObject2)));
+#if !DCHECK_IS_ON()  // DCHECK builds will die at a NOTREACHED().
+  EXPECT_EQ(0U, allocator_->Allocate(TEST_MEMORY_SIZE + 1, 0));
+  allocs_samples = allocator_->allocs_histogram_->SnapshotSamples();
+  EXPECT_EQ(3, allocs_samples->TotalCount());
+  EXPECT_EQ(1, allocs_samples->GetCount(0));
+#endif
+
+  // Check that an objcet's type can be changed.
+  EXPECT_EQ(2U, allocator_->GetType(block2));
+  allocator_->ChangeType(block2, 3, 2);
+  EXPECT_EQ(3U, allocator_->GetType(block2));
+  allocator_->ChangeType(block2, 2, 3);
+  EXPECT_EQ(2U, allocator_->GetType(block2));
+
+  // Create second allocator (read/write) using the same memory segment.
+  std::unique_ptr<PersistentMemoryAllocator> allocator2(
+      new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE,
+                                    TEST_MEMORY_PAGE, 0, "", false));
+  EXPECT_EQ(TEST_ID, allocator2->Id());
+  EXPECT_FALSE(allocator2->used_histogram_);
+  EXPECT_FALSE(allocator2->allocs_histogram_);
+  EXPECT_NE(allocator2->allocs_histogram_, allocator_->allocs_histogram_);
+
+  // Ensure that iteration and access through second allocator works.
+  PersistentMemoryAllocator::Iterator iter2(allocator2.get());
+  EXPECT_EQ(block1, iter2.GetNext(&type));
+  EXPECT_EQ(block2, iter2.GetNext(&type));
+  EXPECT_EQ(0U, iter2.GetNext(&type));
+  EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject1>(block1, 1));
+  EXPECT_NE(nullptr, allocator2->GetAsObject<TestObject2>(block2, 2));
+
+  // Create a third allocator (read-only) using the same memory segment.
+  std::unique_ptr<const PersistentMemoryAllocator> allocator3(
+      new PersistentMemoryAllocator(mem_segment_.get(), TEST_MEMORY_SIZE,
+                                    TEST_MEMORY_PAGE, 0, "", true));
+  EXPECT_EQ(TEST_ID, allocator3->Id());
+  EXPECT_FALSE(allocator3->used_histogram_);
+  EXPECT_FALSE(allocator3->allocs_histogram_);
+
+  // Ensure that iteration and access through third allocator works.
+  PersistentMemoryAllocator::Iterator iter3(allocator3.get());
+  EXPECT_EQ(block1, iter3.GetNext(&type));
+  EXPECT_EQ(block2, iter3.GetNext(&type));
+  EXPECT_EQ(0U, iter3.GetNext(&type));
+  EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject1>(block1, 1));
+  EXPECT_NE(nullptr, allocator3->GetAsObject<TestObject2>(block2, 2));
+
+  // Ensure that GetNextOfType works.
+  PersistentMemoryAllocator::Iterator iter1c(allocator_.get());
+  EXPECT_EQ(block2, iter1c.GetNextOfType(2));
+  EXPECT_EQ(0U, iter1c.GetNextOfType(2));
+}
+
+TEST_F(PersistentMemoryAllocatorTest, PageTest) {
+  // This allocation will go into the first memory page.
+  Reference block1 = allocator_->Allocate(TEST_MEMORY_PAGE / 2, 1);
+  EXPECT_LT(0U, block1);
+  EXPECT_GT(TEST_MEMORY_PAGE, block1);
+
+  // This allocation won't fit in same page as previous block.
+  Reference block2 =
+      allocator_->Allocate(TEST_MEMORY_PAGE - 2 * kAllocAlignment, 2);
+  EXPECT_EQ(TEST_MEMORY_PAGE, block2);
+
+  // This allocation will also require a new page.
+  Reference block3 = allocator_->Allocate(2 * kAllocAlignment + 99, 3);
+  EXPECT_EQ(2U * TEST_MEMORY_PAGE, block3);
+}
+
+// A simple thread that takes an allocator and repeatedly allocates random-
+// sized chunks from it until no more can be done.
+class AllocatorThread : public SimpleThread {
+ public:
+  AllocatorThread(const std::string& name,
+                  void* base,
+                  uint32_t size,
+                  uint32_t page_size)
+      : SimpleThread(name, Options()),
+        count_(0),
+        iterable_(0),
+        allocator_(base, size, page_size, 0, std::string(), false) {}
+
+  void Run() override {
+    for (;;) {
+      uint32_t size = RandInt(1, 99);
+      uint32_t type = RandInt(100, 999);
+      Reference block = allocator_.Allocate(size, type);
+      if (!block)
+        break;
+
+      count_++;
+      if (RandInt(0, 1)) {
+        allocator_.MakeIterable(block);
+        iterable_++;
+      }
+    }
+  }
+
+  unsigned iterable() { return iterable_; }
+  unsigned count() { return count_; }
+
+ private:
+  unsigned count_;
+  unsigned iterable_;
+  PersistentMemoryAllocator allocator_;
+};
+
+// Test parallel allocation/iteration and ensure consistency across all
+// instances.
+TEST_F(PersistentMemoryAllocatorTest, ParallelismTest) {
+  void* memory = mem_segment_.get();
+  AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+
+  t1.Start();
+  t2.Start();
+  t3.Start();
+  t4.Start();
+  t5.Start();
+
+  unsigned last_count = 0;
+  do {
+    unsigned count = CountIterables();
+    EXPECT_LE(last_count, count);
+  } while (!allocator_->IsCorrupt() && !allocator_->IsFull());
+
+  t1.Join();
+  t2.Join();
+  t3.Join();
+  t4.Join();
+  t5.Join();
+
+  EXPECT_FALSE(allocator_->IsCorrupt());
+  EXPECT_TRUE(allocator_->IsFull());
+  EXPECT_EQ(CountIterables(),
+            t1.iterable() + t2.iterable() + t3.iterable() + t4.iterable() +
+            t5.iterable());
+}
+
+// A simple thread that counts objects by iterating through an allocator.
+class CounterThread : public SimpleThread {
+ public:
+  CounterThread(const std::string& name,
+                PersistentMemoryAllocator::Iterator* iterator,
+                Lock* lock,
+                ConditionVariable* condition,
+                bool* wake_up)
+      : SimpleThread(name, Options()),
+        iterator_(iterator),
+        lock_(lock),
+        condition_(condition),
+        count_(0),
+        wake_up_(wake_up) {}
+
+  void Run() override {
+    // Wait so all threads can start at approximately the same time.
+    // Best performance comes from releasing a single worker which then
+    // releases the next, etc., etc.
+    {
+      AutoLock autolock(*lock_);
+
+      // Before calling Wait(), make sure that the wake up condition
+      // has not already passed.  Also, since spurious signal events
+      // are possible, check the condition in a while loop to make
+      // sure that the wake up condition is met when this thread
+      // returns from the Wait().
+      // See usage comments in src/base/synchronization/condition_variable.h.
+      while (!*wake_up_) {
+        condition_->Wait();
+        condition_->Signal();
+      }
+    }
+
+    uint32_t type;
+    while (iterator_->GetNext(&type) != 0) {
+      ++count_;
+    }
+  }
+
+  unsigned count() { return count_; }
+
+ private:
+  PersistentMemoryAllocator::Iterator* iterator_;
+  Lock* lock_;
+  ConditionVariable* condition_;
+  unsigned count_;
+  bool* wake_up_;
+
+  DISALLOW_COPY_AND_ASSIGN(CounterThread);
+};
+
+// Ensure that parallel iteration returns the same number of objects as
+// single-threaded iteration.
+TEST_F(PersistentMemoryAllocatorTest, IteratorParallelismTest) {
+  // Fill the memory segment with random allocations.
+  unsigned iterable_count = 0;
+  for (;;) {
+    uint32_t size = RandInt(1, 99);
+    uint32_t type = RandInt(100, 999);
+    Reference block = allocator_->Allocate(size, type);
+    if (!block)
+      break;
+    allocator_->MakeIterable(block);
+    ++iterable_count;
+  }
+  EXPECT_FALSE(allocator_->IsCorrupt());
+  EXPECT_TRUE(allocator_->IsFull());
+  EXPECT_EQ(iterable_count, CountIterables());
+
+  PersistentMemoryAllocator::Iterator iter(allocator_.get());
+  Lock lock;
+  ConditionVariable condition(&lock);
+  bool wake_up = false;
+
+  CounterThread t1("t1", &iter, &lock, &condition, &wake_up);
+  CounterThread t2("t2", &iter, &lock, &condition, &wake_up);
+  CounterThread t3("t3", &iter, &lock, &condition, &wake_up);
+  CounterThread t4("t4", &iter, &lock, &condition, &wake_up);
+  CounterThread t5("t5", &iter, &lock, &condition, &wake_up);
+
+  t1.Start();
+  t2.Start();
+  t3.Start();
+  t4.Start();
+  t5.Start();
+
+  // Take the lock and set the wake up condition to true.  This helps to
+  // avoid a race condition where the Signal() event is called before
+  // all the threads have reached the Wait() and thus never get woken up.
+  {
+    AutoLock autolock(lock);
+    wake_up = true;
+  }
+
+  // This will release all the waiting threads.
+  condition.Signal();
+
+  t1.Join();
+  t2.Join();
+  t3.Join();
+  t4.Join();
+  t5.Join();
+
+  EXPECT_EQ(iterable_count,
+            t1.count() + t2.count() + t3.count() + t4.count() + t5.count());
+
+#if 0
+  // These ensure that the threads don't run sequentially. It shouldn't be
+  // enabled in general because it could lead to a flaky test if it happens
+  // simply by chance but it is useful during development to ensure that the
+  // test is working correctly.
+  EXPECT_NE(iterable_count, t1.count());
+  EXPECT_NE(iterable_count, t2.count());
+  EXPECT_NE(iterable_count, t3.count());
+  EXPECT_NE(iterable_count, t4.count());
+  EXPECT_NE(iterable_count, t5.count());
+#endif
+}
+
+// This test doesn't verify anything other than it doesn't crash. Its goal
+// is to find coding errors that aren't otherwise tested for, much like a
+// "fuzzer" would.
+// This test is suppsoed to fail on TSAN bot (crbug.com/579867).
+#if defined(THREAD_SANITIZER)
+#define MAYBE_CorruptionTest DISABLED_CorruptionTest
+#else
+#define MAYBE_CorruptionTest CorruptionTest
+#endif
+TEST_F(PersistentMemoryAllocatorTest, MAYBE_CorruptionTest) {
+  char* memory = mem_segment_.get();
+  AllocatorThread t1("t1", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t2("t2", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t3("t3", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t4("t4", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+  AllocatorThread t5("t5", memory, TEST_MEMORY_SIZE, TEST_MEMORY_PAGE);
+
+  t1.Start();
+  t2.Start();
+  t3.Start();
+  t4.Start();
+  t5.Start();
+
+  do {
+    size_t offset = RandInt(0, TEST_MEMORY_SIZE - 1);
+    char value = RandInt(0, 255);
+    memory[offset] = value;
+  } while (!allocator_->IsCorrupt() && !allocator_->IsFull());
+
+  t1.Join();
+  t2.Join();
+  t3.Join();
+  t4.Join();
+  t5.Join();
+
+  CountIterables();
+}
+
+// Attempt to cause crashes or loops by expressly creating dangerous conditions.
+TEST_F(PersistentMemoryAllocatorTest, MaliciousTest) {
+  Reference block1 = allocator_->Allocate(sizeof(TestObject1), 1);
+  Reference block2 = allocator_->Allocate(sizeof(TestObject1), 2);
+  Reference block3 = allocator_->Allocate(sizeof(TestObject1), 3);
+  Reference block4 = allocator_->Allocate(sizeof(TestObject1), 3);
+  Reference block5 = allocator_->Allocate(sizeof(TestObject1), 3);
+  allocator_->MakeIterable(block1);
+  allocator_->MakeIterable(block2);
+  allocator_->MakeIterable(block3);
+  allocator_->MakeIterable(block4);
+  allocator_->MakeIterable(block5);
+  EXPECT_EQ(5U, CountIterables());
+  EXPECT_FALSE(allocator_->IsCorrupt());
+
+  // Create loop in iterable list and ensure it doesn't hang. The return value
+  // from CountIterables() in these cases is unpredictable. If there is a
+  // failure, the call will hang and the test killed for taking too long.
+  uint32_t* header4 = (uint32_t*)(mem_segment_.get() + block4);
+  EXPECT_EQ(block5, header4[3]);
+  header4[3] = block4;
+  CountIterables();  // loop: 1-2-3-4-4
+  EXPECT_TRUE(allocator_->IsCorrupt());
+
+  // Test where loop goes back to previous block.
+  header4[3] = block3;
+  CountIterables();  // loop: 1-2-3-4-3
+
+  // Test where loop goes back to the beginning.
+  header4[3] = block1;
+  CountIterables();  // loop: 1-2-3-4-1
+}
+
+
+//----- LocalPersistentMemoryAllocator -----------------------------------------
+
+TEST(LocalPersistentMemoryAllocatorTest, CreationTest) {
+  LocalPersistentMemoryAllocator allocator(TEST_MEMORY_SIZE, 42, "");
+  EXPECT_EQ(42U, allocator.Id());
+  EXPECT_NE(0U, allocator.Allocate(24, 1));
+  EXPECT_FALSE(allocator.IsFull());
+  EXPECT_FALSE(allocator.IsCorrupt());
+}
+
+
+//----- SharedPersistentMemoryAllocator ----------------------------------------
+
+TEST(SharedPersistentMemoryAllocatorTest, CreationTest) {
+  SharedMemoryHandle shared_handle_1;
+  SharedMemoryHandle shared_handle_2;
+
+  PersistentMemoryAllocator::MemoryInfo meminfo1;
+  Reference r123, r456, r789;
+  {
+    std::unique_ptr<SharedMemory> shmem1(new SharedMemory());
+    ASSERT_TRUE(shmem1->CreateAndMapAnonymous(TEST_MEMORY_SIZE));
+    SharedPersistentMemoryAllocator local(std::move(shmem1), TEST_ID, "",
+                                          false);
+    EXPECT_FALSE(local.IsReadonly());
+    r123 = local.Allocate(123, 123);
+    r456 = local.Allocate(456, 456);
+    r789 = local.Allocate(789, 789);
+    local.MakeIterable(r123);
+    local.ChangeType(r456, 654, 456);
+    local.MakeIterable(r789);
+    local.GetMemoryInfo(&meminfo1);
+    EXPECT_FALSE(local.IsFull());
+    EXPECT_FALSE(local.IsCorrupt());
+
+    ASSERT_TRUE(local.shared_memory()->ShareToProcess(GetCurrentProcessHandle(),
+                                                      &shared_handle_1));
+    ASSERT_TRUE(local.shared_memory()->ShareToProcess(GetCurrentProcessHandle(),
+                                                      &shared_handle_2));
+  }
+
+  // Read-only test.
+  std::unique_ptr<SharedMemory> shmem2(new SharedMemory(shared_handle_1,
+                                                        /*readonly=*/true));
+  ASSERT_TRUE(shmem2->Map(TEST_MEMORY_SIZE));
+
+  SharedPersistentMemoryAllocator shalloc2(std::move(shmem2), 0, "", true);
+  EXPECT_TRUE(shalloc2.IsReadonly());
+  EXPECT_EQ(TEST_ID, shalloc2.Id());
+  EXPECT_FALSE(shalloc2.IsFull());
+  EXPECT_FALSE(shalloc2.IsCorrupt());
+
+  PersistentMemoryAllocator::Iterator iter2(&shalloc2);
+  uint32_t type;
+  EXPECT_EQ(r123, iter2.GetNext(&type));
+  EXPECT_EQ(r789, iter2.GetNext(&type));
+  EXPECT_EQ(0U, iter2.GetNext(&type));
+
+  EXPECT_EQ(123U, shalloc2.GetType(r123));
+  EXPECT_EQ(654U, shalloc2.GetType(r456));
+  EXPECT_EQ(789U, shalloc2.GetType(r789));
+
+  PersistentMemoryAllocator::MemoryInfo meminfo2;
+  shalloc2.GetMemoryInfo(&meminfo2);
+  EXPECT_EQ(meminfo1.total, meminfo2.total);
+  EXPECT_EQ(meminfo1.free, meminfo2.free);
+
+  // Read/write test.
+  std::unique_ptr<SharedMemory> shmem3(new SharedMemory(shared_handle_2,
+                                                        /*readonly=*/false));
+  ASSERT_TRUE(shmem3->Map(TEST_MEMORY_SIZE));
+
+  SharedPersistentMemoryAllocator shalloc3(std::move(shmem3), 0, "", false);
+  EXPECT_FALSE(shalloc3.IsReadonly());
+  EXPECT_EQ(TEST_ID, shalloc3.Id());
+  EXPECT_FALSE(shalloc3.IsFull());
+  EXPECT_FALSE(shalloc3.IsCorrupt());
+
+  PersistentMemoryAllocator::Iterator iter3(&shalloc3);
+  EXPECT_EQ(r123, iter3.GetNext(&type));
+  EXPECT_EQ(r789, iter3.GetNext(&type));
+  EXPECT_EQ(0U, iter3.GetNext(&type));
+
+  EXPECT_EQ(123U, shalloc3.GetType(r123));
+  EXPECT_EQ(654U, shalloc3.GetType(r456));
+  EXPECT_EQ(789U, shalloc3.GetType(r789));
+
+  PersistentMemoryAllocator::MemoryInfo meminfo3;
+  shalloc3.GetMemoryInfo(&meminfo3);
+  EXPECT_EQ(meminfo1.total, meminfo3.total);
+  EXPECT_EQ(meminfo1.free, meminfo3.free);
+
+  // Interconnectivity test.
+  Reference obj = shalloc3.Allocate(42, 42);
+  ASSERT_TRUE(obj);
+  shalloc3.MakeIterable(obj);
+  EXPECT_EQ(obj, iter2.GetNext(&type));
+  EXPECT_EQ(42U, type);
+}
+
+
+#if !defined(OS_NACL)
+//----- FilePersistentMemoryAllocator ------------------------------------------
+
+TEST(FilePersistentMemoryAllocatorTest, CreationTest) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("persistent_memory");
+
+  PersistentMemoryAllocator::MemoryInfo meminfo1;
+  Reference r123, r456, r789;
+  {
+    LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, "");
+    EXPECT_FALSE(local.IsReadonly());
+    r123 = local.Allocate(123, 123);
+    r456 = local.Allocate(456, 456);
+    r789 = local.Allocate(789, 789);
+    local.MakeIterable(r123);
+    local.ChangeType(r456, 654, 456);
+    local.MakeIterable(r789);
+    local.GetMemoryInfo(&meminfo1);
+    EXPECT_FALSE(local.IsFull());
+    EXPECT_FALSE(local.IsCorrupt());
+
+    File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE);
+    ASSERT_TRUE(writer.IsValid());
+    writer.Write(0, (const char*)local.data(), local.used());
+  }
+
+  std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
+  mmfile->Initialize(file_path);
+  EXPECT_TRUE(mmfile->IsValid());
+  const size_t mmlength = mmfile->length();
+  EXPECT_GE(meminfo1.total, mmlength);
+
+  FilePersistentMemoryAllocator file(std::move(mmfile), 0, 0, "", true);
+  EXPECT_TRUE(file.IsReadonly());
+  EXPECT_EQ(TEST_ID, file.Id());
+  EXPECT_FALSE(file.IsFull());
+  EXPECT_FALSE(file.IsCorrupt());
+
+  PersistentMemoryAllocator::Iterator iter(&file);
+  uint32_t type;
+  EXPECT_EQ(r123, iter.GetNext(&type));
+  EXPECT_EQ(r789, iter.GetNext(&type));
+  EXPECT_EQ(0U, iter.GetNext(&type));
+
+  EXPECT_EQ(123U, file.GetType(r123));
+  EXPECT_EQ(654U, file.GetType(r456));
+  EXPECT_EQ(789U, file.GetType(r789));
+
+  PersistentMemoryAllocator::MemoryInfo meminfo2;
+  file.GetMemoryInfo(&meminfo2);
+  EXPECT_GE(meminfo1.total, meminfo2.total);
+  EXPECT_GE(meminfo1.free, meminfo2.free);
+  EXPECT_EQ(mmlength, meminfo2.total);
+  EXPECT_EQ(0U, meminfo2.free);
+}
+
+TEST(FilePersistentMemoryAllocatorTest, ExtendTest) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("extend_test");
+  MemoryMappedFile::Region region = {0, 16 << 10};  // 16KiB maximum size.
+
+  // Start with a small but valid file of persistent data.
+  ASSERT_FALSE(PathExists(file_path));
+  {
+    LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, "");
+    local.Allocate(1, 1);
+    local.Allocate(11, 11);
+
+    File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE);
+    ASSERT_TRUE(writer.IsValid());
+    writer.Write(0, (const char*)local.data(), local.used());
+  }
+  ASSERT_TRUE(PathExists(file_path));
+  int64_t before_size;
+  ASSERT_TRUE(GetFileSize(file_path, &before_size));
+
+  // Map it as an extendable read/write file and append to it.
+  {
+    std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
+    mmfile->Initialize(
+        File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE),
+        region, MemoryMappedFile::READ_WRITE_EXTEND);
+    FilePersistentMemoryAllocator allocator(std::move(mmfile), region.size, 0,
+                                            "", false);
+    EXPECT_EQ(static_cast<size_t>(before_size), allocator.used());
+
+    allocator.Allocate(111, 111);
+    EXPECT_LT(static_cast<size_t>(before_size), allocator.used());
+  }
+
+  // Validate that append worked.
+  int64_t after_size;
+  ASSERT_TRUE(GetFileSize(file_path, &after_size));
+  EXPECT_LT(before_size, after_size);
+
+  // Verify that it's still an acceptable file.
+  {
+    std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
+    mmfile->Initialize(
+        File(file_path, File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE),
+        region, MemoryMappedFile::READ_WRITE_EXTEND);
+    EXPECT_TRUE(FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true));
+    EXPECT_TRUE(
+        FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, false));
+  }
+}
+
+TEST(FilePersistentMemoryAllocatorTest, AcceptableTest) {
+  const uint32_t kAllocAlignment =
+      PersistentMemoryAllocatorTest::GetAllocAlignment();
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  LocalPersistentMemoryAllocator local(TEST_MEMORY_SIZE, TEST_ID, "");
+  local.MakeIterable(local.Allocate(1, 1));
+  local.MakeIterable(local.Allocate(11, 11));
+  const size_t minsize = local.used();
+  std::unique_ptr<char[]> garbage(new char[minsize]);
+  RandBytes(garbage.get(), minsize);
+
+  std::unique_ptr<MemoryMappedFile> mmfile;
+  char filename[100];
+  for (size_t filesize = minsize; filesize > 0; --filesize) {
+    strings::SafeSPrintf(filename, "memory_%d_A", filesize);
+    FilePath file_path = temp_dir.path().AppendASCII(filename);
+    ASSERT_FALSE(PathExists(file_path));
+    {
+      File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE);
+      ASSERT_TRUE(writer.IsValid());
+      writer.Write(0, (const char*)local.data(), filesize);
+    }
+    ASSERT_TRUE(PathExists(file_path));
+
+    // Request read/write access for some sizes that are a multple of the
+    // allocator's alignment size. The allocator is strict about file size
+    // being a multiple of its internal alignment when doing read/write access.
+    const bool read_only = (filesize % (2 * kAllocAlignment)) != 0;
+    const uint32_t file_flags =
+        File::FLAG_OPEN | File::FLAG_READ | (read_only ? 0 : File::FLAG_WRITE);
+    const MemoryMappedFile::Access map_access =
+        read_only ? MemoryMappedFile::READ_ONLY : MemoryMappedFile::READ_WRITE;
+
+    mmfile.reset(new MemoryMappedFile());
+    mmfile->Initialize(File(file_path, file_flags), map_access);
+    EXPECT_EQ(filesize, mmfile->length());
+    if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) {
+      // Make sure construction doesn't crash. It will, however, cause
+      // error messages warning about about a corrupted memory segment.
+      FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "",
+                                              read_only);
+      // Also make sure that iteration doesn't crash.
+      PersistentMemoryAllocator::Iterator iter(&allocator);
+      uint32_t type_id;
+      Reference ref;
+      while ((ref = iter.GetNext(&type_id)) != 0) {
+        const char* data = allocator.GetAsObject<char>(ref, 0);
+        uint32_t type = allocator.GetType(ref);
+        size_t size = allocator.GetAllocSize(ref);
+        // Ensure compiler can't optimize-out above variables.
+        (void)data;
+        (void)type;
+        (void)size;
+      }
+
+      // Ensure that short files are detected as corrupt and full files are not.
+      EXPECT_EQ(filesize != minsize, allocator.IsCorrupt());
+    } else {
+      // For filesize >= minsize, the file must be acceptable. This
+      // else clause (file-not-acceptable) should be reached only if
+      // filesize < minsize.
+      EXPECT_LT(filesize, minsize);
+    }
+
+    strings::SafeSPrintf(filename, "memory_%d_B", filesize);
+    file_path = temp_dir.path().AppendASCII(filename);
+    ASSERT_FALSE(PathExists(file_path));
+    {
+      File writer(file_path, File::FLAG_CREATE | File::FLAG_WRITE);
+      ASSERT_TRUE(writer.IsValid());
+      writer.Write(0, (const char*)garbage.get(), filesize);
+    }
+    ASSERT_TRUE(PathExists(file_path));
+
+    mmfile.reset(new MemoryMappedFile());
+    mmfile->Initialize(File(file_path, file_flags), map_access);
+    EXPECT_EQ(filesize, mmfile->length());
+    if (FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, read_only)) {
+      // Make sure construction doesn't crash. It will, however, cause
+      // error messages warning about about a corrupted memory segment.
+      FilePersistentMemoryAllocator allocator(std::move(mmfile), 0, 0, "",
+                                              read_only);
+      EXPECT_TRUE(allocator.IsCorrupt());  // Garbage data so it should be.
+    } else {
+      // For filesize >= minsize, the file must be acceptable. This
+      // else clause (file-not-acceptable) should be reached only if
+      // filesize < minsize.
+      EXPECT_GT(minsize, filesize);
+    }
+  }
+}
+#endif  // !defined(OS_NACL)
+
+}  // namespace base
diff --git a/libchrome/base/metrics/persistent_sample_map.cc b/libchrome/base/metrics/persistent_sample_map.cc
new file mode 100644
index 0000000..15f83cd
--- /dev/null
+++ b/libchrome/base/metrics/persistent_sample_map.cc
@@ -0,0 +1,289 @@
+// Copyright 2016 The Chromium Authors. All 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/persistent_sample_map.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+namespace {
+
+// An iterator for going through a PersistentSampleMap. The logic here is
+// identical to that of SampleMapIterator but with different data structures.
+// Changes here likely need to be duplicated there.
+class PersistentSampleMapIterator : public SampleCountIterator {
+ public:
+  typedef std::map<HistogramBase::Sample, HistogramBase::Count*>
+      SampleToCountMap;
+
+  explicit PersistentSampleMapIterator(const SampleToCountMap& sample_counts);
+  ~PersistentSampleMapIterator() override;
+
+  // SampleCountIterator:
+  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_;
+};
+
+PersistentSampleMapIterator::PersistentSampleMapIterator(
+    const SampleToCountMap& sample_counts)
+    : iter_(sample_counts.begin()),
+      end_(sample_counts.end()) {
+  SkipEmptyBuckets();
+}
+
+PersistentSampleMapIterator::~PersistentSampleMapIterator() {}
+
+bool PersistentSampleMapIterator::Done() const {
+  return iter_ == end_;
+}
+
+void PersistentSampleMapIterator::Next() {
+  DCHECK(!Done());
+  ++iter_;
+  SkipEmptyBuckets();
+}
+
+void PersistentSampleMapIterator::Get(Sample* min,
+                                      Sample* max,
+                                      Count* count) const {
+  DCHECK(!Done());
+  if (min)
+    *min = iter_->first;
+  if (max)
+    *max = iter_->first + 1;
+  if (count)
+    *count = *iter_->second;
+}
+
+void PersistentSampleMapIterator::SkipEmptyBuckets() {
+  while (!Done() && *iter_->second == 0) {
+    ++iter_;
+  }
+}
+
+// This structure holds an entry for a PersistentSampleMap within a persistent
+// memory allocator. The "id" must be unique across all maps held by an
+// allocator or they will get attached to the wrong sample map.
+struct SampleRecord {
+  uint64_t id;   // Unique identifier of owner.
+  Sample value;  // The value for which this record holds a count.
+  Count count;   // The count associated with the above value.
+};
+
+// The type-id used to identify sample records inside an allocator.
+const uint32_t kTypeIdSampleRecord = 0x8FE6A69F + 1;  // SHA1(SampleRecord) v1
+
+}  // namespace
+
+PersistentSampleMap::PersistentSampleMap(
+    uint64_t id,
+    PersistentHistogramAllocator* allocator,
+    Metadata* meta)
+    : HistogramSamples(id, meta), allocator_(allocator) {}
+
+PersistentSampleMap::~PersistentSampleMap() {
+  if (records_)
+    records_->Release(this);
+}
+
+void PersistentSampleMap::Accumulate(Sample value, Count count) {
+  *GetOrCreateSampleCountStorage(value) += count;
+  IncreaseSum(static_cast<int64_t>(count) * value);
+  IncreaseRedundantCount(count);
+}
+
+Count PersistentSampleMap::GetCount(Sample value) const {
+  // Have to override "const" to make sure all samples have been loaded before
+  // being able to know what value to return.
+  Count* count_pointer =
+      const_cast<PersistentSampleMap*>(this)->GetSampleCountStorage(value);
+  return count_pointer ? *count_pointer : 0;
+}
+
+Count PersistentSampleMap::TotalCount() const {
+  // Have to override "const" in order to make sure all samples have been
+  // loaded before trying to iterate over the map.
+  const_cast<PersistentSampleMap*>(this)->ImportSamples(-1, true);
+
+  Count count = 0;
+  for (const auto& entry : sample_counts_) {
+    count += *entry.second;
+  }
+  return count;
+}
+
+std::unique_ptr<SampleCountIterator> PersistentSampleMap::Iterator() const {
+  // Have to override "const" in order to make sure all samples have been
+  // loaded before trying to iterate over the map.
+  const_cast<PersistentSampleMap*>(this)->ImportSamples(-1, true);
+  return WrapUnique(new PersistentSampleMapIterator(sample_counts_));
+}
+
+// static
+PersistentMemoryAllocator::Reference
+PersistentSampleMap::GetNextPersistentRecord(
+    PersistentMemoryAllocator::Iterator& iterator,
+    uint64_t* sample_map_id) {
+  PersistentMemoryAllocator::Reference ref =
+      iterator.GetNextOfType(kTypeIdSampleRecord);
+  const SampleRecord* record =
+      iterator.GetAsObject<SampleRecord>(ref, kTypeIdSampleRecord);
+  if (!record)
+    return 0;
+
+  *sample_map_id = record->id;
+  return ref;
+}
+
+// static
+PersistentMemoryAllocator::Reference
+PersistentSampleMap::CreatePersistentRecord(
+    PersistentMemoryAllocator* allocator,
+    uint64_t sample_map_id,
+    Sample value) {
+  PersistentMemoryAllocator::Reference ref =
+      allocator->Allocate(sizeof(SampleRecord), kTypeIdSampleRecord);
+  SampleRecord* record =
+      allocator->GetAsObject<SampleRecord>(ref, kTypeIdSampleRecord);
+
+  if (!record) {
+    NOTREACHED() << "full=" << allocator->IsFull()
+                 << ", corrupt=" << allocator->IsCorrupt();
+    return 0;
+  }
+
+  record->id = sample_map_id;
+  record->value = value;
+  record->count = 0;
+  allocator->MakeIterable(ref);
+  return ref;
+}
+
+bool PersistentSampleMap::AddSubtractImpl(SampleCountIterator* iter,
+                                          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.
+
+    *GetOrCreateSampleCountStorage(min) +=
+        (op == HistogramSamples::ADD) ? count : -count;
+  }
+  return true;
+}
+
+Count* PersistentSampleMap::GetSampleCountStorage(Sample value) {
+  // If |value| is already in the map, just return that.
+  auto it = sample_counts_.find(value);
+  if (it != sample_counts_.end())
+    return it->second;
+
+  // Import any new samples from persistent memory looking for the value.
+  return ImportSamples(value, false);
+}
+
+Count* PersistentSampleMap::GetOrCreateSampleCountStorage(Sample value) {
+  // Get any existing count storage.
+  Count* count_pointer = GetSampleCountStorage(value);
+  if (count_pointer)
+    return count_pointer;
+
+  // Create a new record in persistent memory for the value. |records_| will
+  // have been initialized by the GetSampleCountStorage() call above.
+  DCHECK(records_);
+  PersistentMemoryAllocator::Reference ref = records_->CreateNew(value);
+  if (!ref) {
+    // If a new record could not be created then the underlying allocator is
+    // full or corrupt. Instead, allocate the counter from the heap. This
+    // sample will not be persistent, will not be shared, and will leak...
+    // but it's better than crashing.
+    count_pointer = new Count(0);
+    sample_counts_[value] = count_pointer;
+    return count_pointer;
+  }
+
+  // A race condition between two independent processes (i.e. two independent
+  // histogram objects sharing the same sample data) could cause two of the
+  // above records to be created. The allocator, however, forces a strict
+  // ordering on iterable objects so use the import method to actually add the
+  // just-created record. This ensures that all PersistentSampleMap objects
+  // will always use the same record, whichever was first made iterable.
+  // Thread-safety within a process where multiple threads use the same
+  // histogram object is delegated to the controlling histogram object which,
+  // for sparse histograms, is a lock object.
+  count_pointer = ImportSamples(value, false);
+  DCHECK(count_pointer);
+  return count_pointer;
+}
+
+PersistentSampleMapRecords* PersistentSampleMap::GetRecords() {
+  // The |records_| pointer is lazily fetched from the |allocator_| only on
+  // first use. Sometimes duplicate histograms are created by race conditions
+  // and if both were to grab the records object, there would be a conflict.
+  // Use of a histogram, and thus a call to this method, won't occur until
+  // after the histogram has been de-dup'd.
+  if (!records_)
+    records_ = allocator_->UseSampleMapRecords(id(), this);
+  return records_;
+}
+
+Count* PersistentSampleMap::ImportSamples(Sample until_value,
+                                          bool import_everything) {
+  Count* found_count = nullptr;
+  PersistentMemoryAllocator::Reference ref;
+  PersistentSampleMapRecords* records = GetRecords();
+  while ((ref = records->GetNext()) != 0) {
+    SampleRecord* record =
+        records->GetAsObject<SampleRecord>(ref, kTypeIdSampleRecord);
+    if (!record)
+      continue;
+
+    DCHECK_EQ(id(), record->id);
+
+    // Check if the record's value is already known.
+    if (!ContainsKey(sample_counts_, record->value)) {
+      // No: Add it to map of known values.
+      sample_counts_[record->value] = &record->count;
+    } else {
+      // Yes: Ignore it; it's a duplicate caused by a race condition -- see
+      // code & comment in GetOrCreateSampleCountStorage() for details.
+      // Check that nothing ever operated on the duplicate record.
+      DCHECK_EQ(0, record->count);
+    }
+
+    // Check if it's the value being searched for and, if so, keep a pointer
+    // to return later. Stop here unless everything is being imported.
+    // Because race conditions can cause multiple records for a single value,
+    // be sure to return the first one found.
+    if (record->value == until_value) {
+      if (!found_count)
+        found_count = &record->count;
+      if (!import_everything)
+        break;
+    }
+  }
+
+  return found_count;
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/persistent_sample_map.h b/libchrome/base/metrics/persistent_sample_map.h
new file mode 100644
index 0000000..3c175db
--- /dev/null
+++ b/libchrome/base/metrics/persistent_sample_map.h
@@ -0,0 +1,110 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// PersistentSampleMap implements HistogramSamples interface. It is used
+// by the SparseHistogram class to store samples in persistent memory which
+// allows it to be shared between processes or live across restarts.
+
+#ifndef BASE_METRICS_PERSISTENT_SAMPLE_MAP_H_
+#define BASE_METRICS_PERSISTENT_SAMPLE_MAP_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/persistent_memory_allocator.h"
+
+namespace base {
+
+class PersistentHistogramAllocator;
+class PersistentSampleMapRecords;
+class PersistentSparseHistogramDataManager;
+
+// The logic here is similar to that of SampleMap but with different data
+// structures. Changes here likely need to be duplicated there.
+class BASE_EXPORT PersistentSampleMap : public HistogramSamples {
+ public:
+  // Constructs a persistent sample map using a PersistentHistogramAllocator
+  // as the data source for persistent records.
+  PersistentSampleMap(uint64_t id,
+                      PersistentHistogramAllocator* allocator,
+                      Metadata* meta);
+
+  ~PersistentSampleMap() override;
+
+  // HistogramSamples:
+  void Accumulate(HistogramBase::Sample value,
+                  HistogramBase::Count count) override;
+  HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
+  HistogramBase::Count TotalCount() const override;
+  std::unique_ptr<SampleCountIterator> Iterator() const override;
+
+  // Uses a persistent-memory |iterator| to locate and return information about
+  // the next record holding information for a PersistentSampleMap. The record
+  // could be for any Map so return the |sample_map_id| as well.
+  static PersistentMemoryAllocator::Reference GetNextPersistentRecord(
+      PersistentMemoryAllocator::Iterator& iterator,
+      uint64_t* sample_map_id);
+
+  // Creates a new record in an |allocator| storing count information for a
+  // specific sample |value| of a histogram with the given |sample_map_id|.
+  static PersistentMemoryAllocator::Reference CreatePersistentRecord(
+      PersistentMemoryAllocator* allocator,
+      uint64_t sample_map_id,
+      HistogramBase::Sample value);
+
+ protected:
+  // Performs arithemetic. |op| is ADD or SUBTRACT.
+  bool AddSubtractImpl(SampleCountIterator* iter, Operator op) override;
+
+  // Gets a pointer to a "count" corresponding to a given |value|. Returns NULL
+  // if sample does not exist.
+  HistogramBase::Count* GetSampleCountStorage(HistogramBase::Sample value);
+
+  // Gets a pointer to a "count" corresponding to a given |value|, creating
+  // the sample (initialized to zero) if it does not already exists.
+  HistogramBase::Count* GetOrCreateSampleCountStorage(
+      HistogramBase::Sample value);
+
+ private:
+  // Gets the object that manages persistent records. This returns the
+  // |records_| member after first initializing it if necessary.
+  PersistentSampleMapRecords* GetRecords();
+
+  // Imports samples from persistent memory by iterating over all sample
+  // records found therein, adding them to the sample_counts_ map. If a
+  // count for the sample |until_value| is found, stop the import and return
+  // a pointer to that counter. If that value is not found, null will be
+  // returned after all currently available samples have been loaded. Pass
+  // true for |import_everything| to force the importing of all available
+  // samples even if a match is found.
+  HistogramBase::Count* ImportSamples(HistogramBase::Sample until_value,
+                                      bool import_everything);
+
+  // All created/loaded sample values and their associated counts. The storage
+  // for the actual Count numbers is owned by the |records_| object and its
+  // underlying allocator.
+  std::map<HistogramBase::Sample, HistogramBase::Count*> sample_counts_;
+
+  // The allocator that manages histograms inside persistent memory. This is
+  // owned externally and is expected to live beyond the life of this object.
+  PersistentHistogramAllocator* allocator_;
+
+  // The object that manages sample records inside persistent memory. This is
+  // owned by the |allocator_| object (above) and so, like it, is expected to
+  // live beyond the life of this object. This value is lazily-initialized on
+  // first use via the GetRecords() accessor method.
+  PersistentSampleMapRecords* records_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(PersistentSampleMap);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_PERSISTENT_SAMPLE_MAP_H_
diff --git a/libchrome/base/metrics/persistent_sample_map_unittest.cc b/libchrome/base/metrics/persistent_sample_map_unittest.cc
new file mode 100644
index 0000000..beb72e5
--- /dev/null
+++ b/libchrome/base/metrics/persistent_sample_map_unittest.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2016 The Chromium Authors. All 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/persistent_sample_map.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+std::unique_ptr<PersistentHistogramAllocator> CreateHistogramAllocator(
+    size_t bytes) {
+  return WrapUnique(new PersistentHistogramAllocator(
+      WrapUnique(new LocalPersistentMemoryAllocator(bytes, 0, ""))));
+}
+
+std::unique_ptr<PersistentHistogramAllocator> DuplicateHistogramAllocator(
+    PersistentHistogramAllocator* original) {
+  return WrapUnique(
+      new PersistentHistogramAllocator(WrapUnique(new PersistentMemoryAllocator(
+          const_cast<void*>(original->data()), original->length(), 0,
+          original->Id(), original->Name(), false))));
+}
+
+TEST(PersistentSampleMapTest, AccumulateTest) {
+  std::unique_ptr<PersistentHistogramAllocator> allocator =
+      CreateHistogramAllocator(64 << 10);  // 64 KiB
+  HistogramSamples::Metadata meta;
+  PersistentSampleMap samples(1, allocator.get(), &meta);
+
+  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(PersistentSampleMapTest, Accumulate_LargeValuesDontOverflow) {
+  std::unique_ptr<PersistentHistogramAllocator> allocator =
+      CreateHistogramAllocator(64 << 10);  // 64 KiB
+  HistogramSamples::Metadata meta;
+  PersistentSampleMap samples(1, allocator.get(), &meta);
+
+  samples.Accumulate(250000000, 100);
+  samples.Accumulate(500000000, 200);
+  samples.Accumulate(250000000, -200);
+  EXPECT_EQ(-100, samples.GetCount(250000000));
+  EXPECT_EQ(200, samples.GetCount(500000000));
+
+  EXPECT_EQ(75000000000LL, samples.sum());
+  EXPECT_EQ(100, samples.TotalCount());
+  EXPECT_EQ(samples.redundant_count(), samples.TotalCount());
+}
+
+TEST(PersistentSampleMapTest, AddSubtractTest) {
+  std::unique_ptr<PersistentHistogramAllocator> allocator1 =
+      CreateHistogramAllocator(64 << 10);  // 64 KiB
+  HistogramSamples::Metadata meta1;
+  PersistentSampleMap samples1(1, allocator1.get(), &meta1);
+  samples1.Accumulate(1, 100);
+  samples1.Accumulate(2, 100);
+  samples1.Accumulate(3, 100);
+
+  std::unique_ptr<PersistentHistogramAllocator> allocator2 =
+      DuplicateHistogramAllocator(allocator1.get());
+  HistogramSamples::Metadata meta2;
+  PersistentSampleMap samples2(2, allocator2.get(), &meta2);
+  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(PersistentSampleMapTest, PersistenceTest) {
+  std::unique_ptr<PersistentHistogramAllocator> allocator1 =
+      CreateHistogramAllocator(64 << 10);  // 64 KiB
+  HistogramSamples::Metadata meta12;
+  PersistentSampleMap samples1(12, allocator1.get(), &meta12);
+  samples1.Accumulate(1, 100);
+  samples1.Accumulate(2, 200);
+  samples1.Accumulate(1, -200);
+  samples1.Accumulate(-1, 1);
+  EXPECT_EQ(-100, samples1.GetCount(1));
+  EXPECT_EQ(200, samples1.GetCount(2));
+  EXPECT_EQ(1, samples1.GetCount(-1));
+  EXPECT_EQ(299, samples1.sum());
+  EXPECT_EQ(101, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  std::unique_ptr<PersistentHistogramAllocator> allocator2 =
+      DuplicateHistogramAllocator(allocator1.get());
+  PersistentSampleMap samples2(12, allocator2.get(), &meta12);
+  EXPECT_EQ(samples1.id(), samples2.id());
+  EXPECT_EQ(samples1.sum(), samples2.sum());
+  EXPECT_EQ(samples1.redundant_count(), samples2.redundant_count());
+  EXPECT_EQ(samples1.TotalCount(), samples2.TotalCount());
+  EXPECT_EQ(-100, samples2.GetCount(1));
+  EXPECT_EQ(200, samples2.GetCount(2));
+  EXPECT_EQ(1, samples2.GetCount(-1));
+  EXPECT_EQ(299, samples2.sum());
+  EXPECT_EQ(101, samples2.TotalCount());
+  EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount());
+
+  samples1.Accumulate(-1, -1);
+  EXPECT_EQ(0, samples2.GetCount(3));
+  EXPECT_EQ(0, samples1.GetCount(3));
+  samples2.Accumulate(3, 300);
+  EXPECT_EQ(300, samples2.GetCount(3));
+  EXPECT_EQ(300, samples1.GetCount(3));
+  EXPECT_EQ(samples1.sum(), samples2.sum());
+  EXPECT_EQ(samples1.redundant_count(), samples2.redundant_count());
+  EXPECT_EQ(samples1.TotalCount(), samples2.TotalCount());
+
+  EXPECT_EQ(0, samples2.GetCount(4));
+  EXPECT_EQ(0, samples1.GetCount(4));
+  samples1.Accumulate(4, 400);
+  EXPECT_EQ(400, samples2.GetCount(4));
+  EXPECT_EQ(400, samples1.GetCount(4));
+  samples2.Accumulate(4, 4000);
+  EXPECT_EQ(4400, samples2.GetCount(4));
+  EXPECT_EQ(4400, samples1.GetCount(4));
+  EXPECT_EQ(samples1.sum(), samples2.sum());
+  EXPECT_EQ(samples1.redundant_count(), samples2.redundant_count());
+  EXPECT_EQ(samples1.TotalCount(), samples2.TotalCount());
+}
+
+TEST(PersistentSampleMapIteratorTest, IterateTest) {
+  std::unique_ptr<PersistentHistogramAllocator> allocator =
+      CreateHistogramAllocator(64 << 10);  // 64 KiB
+  HistogramSamples::Metadata meta;
+  PersistentSampleMap samples(1, allocator.get(), &meta);
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(4, -300);
+  samples.Accumulate(5, 0);
+
+  std::unique_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(PersistentSampleMapIteratorTest, SkipEmptyRanges) {
+  std::unique_ptr<PersistentHistogramAllocator> allocator1 =
+      CreateHistogramAllocator(64 << 10);  // 64 KiB
+  HistogramSamples::Metadata meta1;
+  PersistentSampleMap samples1(1, allocator1.get(), &meta1);
+  samples1.Accumulate(5, 1);
+  samples1.Accumulate(10, 2);
+  samples1.Accumulate(15, 3);
+  samples1.Accumulate(20, 4);
+  samples1.Accumulate(25, 5);
+
+  std::unique_ptr<PersistentHistogramAllocator> allocator2 =
+      DuplicateHistogramAllocator(allocator1.get());
+  HistogramSamples::Metadata meta2;
+  PersistentSampleMap samples2(2, allocator2.get(), &meta2);
+  samples2.Accumulate(5, 1);
+  samples2.Accumulate(20, 4);
+  samples2.Accumulate(25, 5);
+
+  samples1.Subtract(samples2);
+
+  std::unique_ptr<SampleCountIterator> it = samples1.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());
+}
+
+// Only run this test on builds that support catching a DCHECK crash.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+TEST(PersistentSampleMapIteratorDeathTest, IterateDoneTest) {
+  std::unique_ptr<PersistentHistogramAllocator> allocator =
+      CreateHistogramAllocator(64 << 10);  // 64 KiB
+  HistogramSamples::Metadata meta;
+  PersistentSampleMap samples(1, allocator.get(), &meta);
+
+  std::unique_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/libchrome/base/metrics/sample_map.cc b/libchrome/base/metrics/sample_map.cc
new file mode 100644
index 0000000..8abd01e
--- /dev/null
+++ b/libchrome/base/metrics/sample_map.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/metrics/sample_map.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+namespace {
+
+// An iterator for going through a SampleMap. The logic here is identical
+// to that of PersistentSampleMapIterator but with different data structures.
+// Changes here likely need to be duplicated there.
+class SampleMapIterator : public SampleCountIterator {
+ public:
+  typedef std::map<HistogramBase::Sample, HistogramBase::Count>
+      SampleToCountMap;
+
+  explicit SampleMapIterator(const SampleToCountMap& sample_counts);
+  ~SampleMapIterator() override;
+
+  // SampleCountIterator:
+  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_;
+};
+
+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)
+    *min = iter_->first;
+  if (max)
+    *max = iter_->first + 1;
+  if (count)
+    *count = iter_->second;
+}
+
+void SampleMapIterator::SkipEmptyBuckets() {
+  while (!Done() && iter_->second == 0) {
+    ++iter_;
+  }
+}
+
+}  // namespace
+
+SampleMap::SampleMap() : SampleMap(0) {}
+
+SampleMap::SampleMap(uint64_t id) : HistogramSamples(id) {}
+
+SampleMap::~SampleMap() {}
+
+void SampleMap::Accumulate(Sample value, Count count) {
+  sample_counts_[value] += count;
+  IncreaseSum(static_cast<int64_t>(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;
+}
+
+std::unique_ptr<SampleCountIterator> SampleMap::Iterator() const {
+  return WrapUnique(new SampleMapIterator(sample_counts_));
+}
+
+bool SampleMap::AddSubtractImpl(SampleCountIterator* iter, 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;
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/sample_map.h b/libchrome/base/metrics/sample_map.h
new file mode 100644
index 0000000..7458e05
--- /dev/null
+++ b/libchrome/base/metrics/sample_map.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.
+
+// 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 <stdint.h>
+
+#include <map>
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+// The logic here is similar to that of PersistentSampleMap but with different
+// data structures. Changes here likely need to be duplicated there.
+class BASE_EXPORT SampleMap : public HistogramSamples {
+ public:
+  SampleMap();
+  explicit SampleMap(uint64_t id);
+  ~SampleMap() override;
+
+  // HistogramSamples:
+  void Accumulate(HistogramBase::Sample value,
+                  HistogramBase::Count count) override;
+  HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
+  HistogramBase::Count TotalCount() const override;
+  std::unique_ptr<SampleCountIterator> Iterator() const override;
+
+ protected:
+  // Performs arithemetic. |op| is ADD or SUBTRACT.
+  bool AddSubtractImpl(SampleCountIterator* iter, Operator op) override;
+
+ private:
+  std::map<HistogramBase::Sample, HistogramBase::Count> sample_counts_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleMap);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_MAP_H_
diff --git a/libchrome/base/metrics/sample_map_unittest.cc b/libchrome/base/metrics/sample_map_unittest.cc
new file mode 100644
index 0000000..8f57710
--- /dev/null
+++ b/libchrome/base/metrics/sample_map_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/metrics/sample_map.h"
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(SampleMapTest, AccumulateTest) {
+  SampleMap samples(1);
+
+  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, Accumulate_LargeValuesDontOverflow) {
+  SampleMap samples(1);
+
+  samples.Accumulate(250000000, 100);
+  samples.Accumulate(500000000, 200);
+  samples.Accumulate(250000000, -200);
+  EXPECT_EQ(-100, samples.GetCount(250000000));
+  EXPECT_EQ(200, samples.GetCount(500000000));
+
+  EXPECT_EQ(75000000000LL, samples.sum());
+  EXPECT_EQ(100, samples.TotalCount());
+  EXPECT_EQ(samples.redundant_count(), samples.TotalCount());
+}
+
+TEST(SampleMapTest, AddSubtractTest) {
+  SampleMap samples1(1);
+  SampleMap samples2(2);
+
+  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(1);
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(4, -300);
+  samples.Accumulate(5, 0);
+
+  std::unique_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(1);
+  samples.Accumulate(5, 1);
+  samples.Accumulate(10, 2);
+  samples.Accumulate(15, 3);
+  samples.Accumulate(20, 4);
+  samples.Accumulate(25, 5);
+
+  SampleMap samples2(2);
+  samples2.Accumulate(5, 1);
+  samples2.Accumulate(20, 4);
+  samples2.Accumulate(25, 5);
+
+  samples.Subtract(samples2);
+
+  std::unique_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(1);
+
+  std::unique_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/libchrome/base/metrics/sample_vector.cc b/libchrome/base/metrics/sample_vector.cc
new file mode 100644
index 0000000..7b056cb
--- /dev/null
+++ b/libchrome/base/metrics/sample_vector.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/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)
+    : SampleVector(0, bucket_ranges) {}
+
+SampleVector::SampleVector(uint64_t id, const BucketRanges* bucket_ranges)
+    : HistogramSamples(id),
+      local_counts_(bucket_ranges->bucket_count()),
+      counts_(&local_counts_[0]),
+      counts_size_(local_counts_.size()),
+      bucket_ranges_(bucket_ranges) {
+  CHECK_GE(bucket_ranges_->bucket_count(), 1u);
+}
+
+SampleVector::SampleVector(uint64_t id,
+                           HistogramBase::AtomicCount* counts,
+                           size_t /*counts_size*/,
+                           Metadata* meta,
+                           const BucketRanges* bucket_ranges)
+    : HistogramSamples(id, meta),
+      counts_(counts),
+      counts_size_(bucket_ranges->bucket_count()),
+      bucket_ranges_(bucket_ranges) {
+  CHECK_LE(bucket_ranges_->bucket_count(), counts_size_);
+  CHECK_GE(bucket_ranges_->bucket_count(), 1u);
+}
+
+SampleVector::~SampleVector() {}
+
+void SampleVector::Accumulate(Sample value, Count count) {
+  size_t bucket_index = GetBucketIndex(value);
+  subtle::NoBarrier_AtomicIncrement(&counts_[bucket_index], count);
+  IncreaseSum(static_cast<int64_t>(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]);
+}
+
+std::unique_ptr<SampleCountIterator> SampleVector::Iterator() const {
+  return std::unique_ptr<SampleCountIterator>(
+      new SampleVectorIterator(counts_, counts_size_, 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!
+      subtle::NoBarrier_AtomicIncrement(
+          &counts_[index], 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<HistogramBase::AtomicCount>* counts,
+    const BucketRanges* bucket_ranges)
+    : counts_(&(*counts)[0]),
+      counts_size_(counts->size()),
+      bucket_ranges_(bucket_ranges),
+      index_(0) {
+  CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
+  SkipEmptyBuckets();
+}
+
+SampleVectorIterator::SampleVectorIterator(
+    const HistogramBase::AtomicCount* counts,
+    size_t counts_size,
+    const BucketRanges* bucket_ranges)
+    : counts_(counts),
+      counts_size_(counts_size),
+      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/libchrome/base/metrics/sample_vector.h b/libchrome/base/metrics/sample_vector.h
new file mode 100644
index 0000000..ee26c52
--- /dev/null
+++ b/libchrome/base/metrics/sample_vector.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium 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 <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+class BucketRanges;
+
+class BASE_EXPORT SampleVector : public HistogramSamples {
+ public:
+  explicit SampleVector(const BucketRanges* bucket_ranges);
+  SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
+  SampleVector(uint64_t id,
+               HistogramBase::AtomicCount* counts,
+               size_t counts_size,
+               Metadata* meta,
+               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;
+  std::unique_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);
+  FRIEND_TEST_ALL_PREFIXES(SharedHistogramTest, CorruptSampleCounts);
+
+  // In the case where this class manages the memory, here it is.
+  std::vector<HistogramBase::AtomicCount> local_counts_;
+
+  // These are raw pointers rather than objects for flexibility. The actual
+  // memory is either managed by local_counts_ above or by an external object
+  // and passed in directly.
+  HistogramBase::AtomicCount* counts_;
+  size_t counts_size_;
+
+  // Shares the same BucketRanges with Histogram object.
+  const BucketRanges* const bucket_ranges_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleVector);
+};
+
+class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
+ public:
+  SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
+                       const BucketRanges* bucket_ranges);
+  SampleVectorIterator(const HistogramBase::AtomicCount* counts,
+                       size_t counts_size,
+                       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 HistogramBase::AtomicCount* counts_;
+  size_t counts_size_;
+  const BucketRanges* bucket_ranges_;
+
+  size_t index_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_VECTOR_H_
diff --git a/libchrome/base/metrics/sample_vector_unittest.cc b/libchrome/base/metrics/sample_vector_unittest.cc
new file mode 100644
index 0000000..02e48aa
--- /dev/null
+++ b/libchrome/base/metrics/sample_vector_unittest.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/metrics/sample_vector.h"
+
+#include <limits.h>
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#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(1, &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, Accumulate_LargeValuesDontOverflow) {
+  // Custom buckets: [1, 250000000) [250000000, 500000000)
+  BucketRanges ranges(3);
+  ranges.set_range(0, 1);
+  ranges.set_range(1, 250000000);
+  ranges.set_range(2, 500000000);
+  SampleVector samples(1, &ranges);
+
+  samples.Accumulate(240000000, 200);
+  samples.Accumulate(249999999, -300);
+  EXPECT_EQ(-100, samples.GetCountAtIndex(0));
+
+  samples.Accumulate(250000000, 200);
+  EXPECT_EQ(200, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(23000000300LL, samples.sum());
+  EXPECT_EQ(100, samples.redundant_count());
+  EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
+
+  samples.Accumulate(250000000, -100);
+  EXPECT_EQ(100, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(-1999999700LL, 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(1, &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(2, &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(1, &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(2, &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(1, &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(2, &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(1, &ranges);
+  samples.Accumulate(0, 0);
+  samples.Accumulate(1, 1);
+  samples.Accumulate(2, 2);
+  samples.Accumulate(3, 3);
+  std::unique_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(1, &ranges);
+
+  std::unique_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/libchrome/base/metrics/sparse_histogram.cc b/libchrome/base/metrics/sparse_histogram.cc
new file mode 100644
index 0000000..3c1222d
--- /dev/null
+++ b/libchrome/base/metrics/sparse_histogram.cc
@@ -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.
+
+#include "base/metrics/sparse_histogram.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/metrics/metrics_hashes.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_sample_map.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_t flags) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // Try to create the histogram using a "persistent" allocator. As of
+    // 2016-02-25, the availability of such is controlled by a base::Feature
+    // that is off by default. If the allocator doesn't exist or if
+    // allocating from it fails, code below will allocate the histogram from
+    // the process heap.
+    PersistentMemoryAllocator::Reference histogram_ref = 0;
+    std::unique_ptr<HistogramBase> tentative_histogram;
+    PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
+    if (allocator) {
+      tentative_histogram = allocator->AllocateHistogram(
+          SPARSE_HISTOGRAM, name, 0, 0, nullptr, flags, &histogram_ref);
+    }
+
+    // Handle the case where no persistent allocator is present or the
+    // persistent allocation fails (perhaps because it is full).
+    if (!tentative_histogram) {
+      DCHECK(!histogram_ref);  // Should never have been set.
+      DCHECK(!allocator);      // Shouldn't have failed.
+      flags &= ~HistogramBase::kIsPersistent;
+      tentative_histogram.reset(new SparseHistogram(name));
+      tentative_histogram->SetFlags(flags);
+    }
+
+    // Register this histogram with the StatisticsRecorder. Keep a copy of
+    // the pointer value to tell later whether the locally created histogram
+    // was registered or deleted. The type is "void" because it could point
+    // to released memory after the following line.
+    const void* tentative_histogram_ptr = tentative_histogram.get();
+    histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
+        tentative_histogram.release());
+
+    // Persistent histograms need some follow-up processing.
+    if (histogram_ref) {
+      allocator->FinalizeHistogram(histogram_ref,
+                                   histogram == tentative_histogram_ptr);
+    }
+
+    ReportHistogramActivity(*histogram, HISTOGRAM_CREATED);
+  } else {
+    ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP);
+  }
+
+  DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
+  return histogram;
+}
+
+// static
+std::unique_ptr<HistogramBase> SparseHistogram::PersistentCreate(
+    PersistentHistogramAllocator* allocator,
+    const std::string& name,
+    HistogramSamples::Metadata* meta,
+    HistogramSamples::Metadata* logged_meta) {
+  return WrapUnique(
+      new SparseHistogram(allocator, name, meta, logged_meta));
+}
+
+SparseHistogram::~SparseHistogram() {}
+
+uint64_t SparseHistogram::name_hash() const {
+  return samples_->id();
+}
+
+HistogramType SparseHistogram::GetHistogramType() const {
+  return SPARSE_HISTOGRAM;
+}
+
+bool SparseHistogram::HasConstructionArguments(
+    Sample /*expected_minimum*/,
+    Sample /*expected_maximum*/,
+    uint32_t /*expected_bucket_count*/) const {
+  // SparseHistogram never has min/max/bucket_count limit.
+  return false;
+}
+
+void SparseHistogram::Add(Sample value) {
+  AddCount(value, 1);
+}
+
+void SparseHistogram::AddCount(Sample value, int count) {
+  if (count <= 0) {
+    NOTREACHED();
+    return;
+  }
+  {
+    base::AutoLock auto_lock(lock_);
+    samples_->Accumulate(value, count);
+  }
+
+  FindAndRunCallback(value);
+}
+
+std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
+  std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
+
+  base::AutoLock auto_lock(lock_);
+  snapshot->Add(*samples_);
+  return std::move(snapshot);
+}
+
+std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotDelta() {
+  DCHECK(!final_delta_created_);
+
+  std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
+  base::AutoLock auto_lock(lock_);
+  snapshot->Add(*samples_);
+
+  // Subtract what was previously logged and update that information.
+  snapshot->Subtract(*logged_samples_);
+  logged_samples_->Add(*snapshot);
+  return std::move(snapshot);
+}
+
+std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotFinalDelta() const {
+  DCHECK(!final_delta_created_);
+  final_delta_created_ = true;
+
+  std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
+  base::AutoLock auto_lock(lock_);
+  snapshot->Add(*samples_);
+
+  // Subtract what was previously logged and then return.
+  snapshot->Subtract(*logged_samples_);
+  return std::move(snapshot);
+}
+
+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),
+      samples_(new SampleMap(HashMetricName(name))),
+      logged_samples_(new SampleMap(samples_->id())) {}
+
+SparseHistogram::SparseHistogram(PersistentHistogramAllocator* allocator,
+                                 const std::string& name,
+                                 HistogramSamples::Metadata* meta,
+                                 HistogramSamples::Metadata* logged_meta)
+    : HistogramBase(name),
+      // While other histogram types maintain a static vector of values with
+      // sufficient space for both "active" and "logged" samples, with each
+      // SampleVector being given the appropriate half, sparse histograms
+      // have no such initial allocation. Each sample has its own record
+      // attached to a single PersistentSampleMap by a common 64-bit identifier.
+      // Since a sparse histogram has two sample maps (active and logged),
+      // there must be two sets of sample records with diffent IDs. The
+      // "active" samples use, for convenience purposes, an ID matching
+      // that of the histogram while the "logged" samples use that number
+      // plus 1.
+      samples_(new PersistentSampleMap(HashMetricName(name), allocator, meta)),
+      logged_samples_(
+          new PersistentSampleMap(samples_->id() + 1, allocator, logged_meta)) {
+}
+
+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;
+  }
+
+  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_t* /*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.
+  std::unique_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;
+  std::unique_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/libchrome/base/metrics/sparse_histogram.h b/libchrome/base/metrics/sparse_histogram.h
new file mode 100644
index 0000000..3b302d6
--- /dev/null
+++ b/libchrome/base/metrics/sparse_histogram.h
@@ -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.
+
+#ifndef BASE_METRICS_SPARSE_HISTOGRAM_H_
+#define BASE_METRICS_SPARSE_HISTOGRAM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/sample_map.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// Sparse histograms are well suited for recording counts of exact sample values
+// that are sparsely distributed over a large range.
+//
+// The implementation uses a lock and a map, whereas other histogram types use a
+// vector and no lock. It is thus more costly to add values to, and each value
+// stored has more overhead, compared to the other histogram types. However it
+// may be more efficient in memory if the total number of sample values is small
+// compared to the range of their values.
+//
+// UMA_HISTOGRAM_ENUMERATION would be better suited for a smaller range of
+// enumerations that are (nearly) contiguous. Also for code that is expected to
+// run often or in a tight loop.
+//
+// UMA_HISTOGRAM_SPARSE_SLOWLY is good for sparsely distributed and or
+// infrequently recorded values.
+//
+// For instance, Sqlite.Version.* are SPARSE because for any given database,
+// there's going to be exactly one version logged, meaning no gain to having a
+// pre-allocated vector of slots once the fleet gets to version 4 or 5 or 10.
+// Likewise Sqlite.Error.* are SPARSE, because most databases generate few or no
+// errors and there are large gaps in the set of possible errors.
+#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 PersistentHistogramAllocator;
+
+class BASE_EXPORT 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_t flags);
+
+  // Create a histogram using data in persistent storage. The allocator must
+  // live longer than the created sparse histogram.
+  static std::unique_ptr<HistogramBase> PersistentCreate(
+      PersistentHistogramAllocator* allocator,
+      const std::string& name,
+      HistogramSamples::Metadata* meta,
+      HistogramSamples::Metadata* logged_meta);
+
+  ~SparseHistogram() override;
+
+  // HistogramBase implementation:
+  uint64_t name_hash() const override;
+  HistogramType GetHistogramType() const override;
+  bool HasConstructionArguments(Sample expected_minimum,
+                                Sample expected_maximum,
+                                uint32_t expected_bucket_count) const override;
+  void Add(Sample value) override;
+  void AddCount(Sample value, int count) override;
+  void AddSamples(const HistogramSamples& samples) override;
+  bool AddSamplesFromPickle(base::PickleIterator* iter) override;
+  std::unique_ptr<HistogramSamples> SnapshotSamples() const override;
+  std::unique_ptr<HistogramSamples> SnapshotDelta() override;
+  std::unique_ptr<HistogramSamples> SnapshotFinalDelta() 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);
+
+  SparseHistogram(PersistentHistogramAllocator* allocator,
+                  const std::string& name,
+                  HistogramSamples::Metadata* meta,
+                  HistogramSamples::Metadata* logged_meta);
+
+  friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  void GetParameters(DictionaryValue* params) const override;
+  void GetCountAndBucketData(Count* count,
+                             int64_t* 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_;
+
+  // Flag to indicate if PrepareFinalDelta has been previously called.
+  mutable bool final_delta_created_ = false;
+
+  std::unique_ptr<HistogramSamples> samples_;
+  std::unique_ptr<HistogramSamples> logged_samples_;
+
+  DISALLOW_COPY_AND_ASSIGN(SparseHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SPARSE_HISTOGRAM_H_
diff --git a/libchrome/base/metrics/sparse_histogram_unittest.cc b/libchrome/base/metrics/sparse_histogram_unittest.cc
new file mode 100644
index 0000000..eab7790
--- /dev/null
+++ b/libchrome/base/metrics/sparse_histogram_unittest.cc
@@ -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.
+
+#include "base/metrics/sparse_histogram.h"
+
+#include <memory>
+#include <string>
+
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_memory_allocator.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 {
+
+// Test parameter indicates if a persistent memory allocator should be used
+// for histogram allocation. False will allocate histograms from the process
+// heap.
+class SparseHistogramTest : public testing::TestWithParam<bool> {
+ protected:
+  const int32_t kAllocatorMemorySize = 8 << 20;  // 8 MiB
+
+  SparseHistogramTest() : use_persistent_histogram_allocator_(GetParam()) {}
+
+  void SetUp() override {
+    if (use_persistent_histogram_allocator_)
+      CreatePersistentMemoryAllocator();
+
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override {
+    if (allocator_) {
+      ASSERT_FALSE(allocator_->IsFull());
+      ASSERT_FALSE(allocator_->IsCorrupt());
+    }
+    UninitializeStatisticsRecorder();
+    DestroyPersistentMemoryAllocator();
+  }
+
+  void InitializeStatisticsRecorder() {
+    DCHECK(!statistics_recorder_);
+    statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    statistics_recorder_.reset();
+  }
+
+  void CreatePersistentMemoryAllocator() {
+    // By getting the results-histogram before any persistent allocator
+    // is attached, that histogram is guaranteed not to be stored in
+    // any persistent memory segment (which simplifies some tests).
+    GlobalHistogramAllocator::GetCreateHistogramResultHistogram();
+
+    GlobalHistogramAllocator::CreateWithLocalMemory(
+        kAllocatorMemorySize, 0, "SparseHistogramAllocatorTest");
+    allocator_ = GlobalHistogramAllocator::Get()->memory_allocator();
+  }
+
+  void DestroyPersistentMemoryAllocator() {
+    allocator_ = nullptr;
+    GlobalHistogramAllocator::ReleaseForTesting();
+  }
+
+  std::unique_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) {
+    return std::unique_ptr<SparseHistogram>(new SparseHistogram(name));
+  }
+
+  const bool use_persistent_histogram_allocator_;
+
+  std::unique_ptr<StatisticsRecorder> statistics_recorder_;
+  PersistentMemoryAllocator* allocator_ = nullptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SparseHistogramTest);
+};
+
+// Run all HistogramTest cases with both heap and persistent memory.
+INSTANTIATE_TEST_CASE_P(HeapAndPersistent,
+                        SparseHistogramTest,
+                        testing::Bool());
+
+
+TEST_P(SparseHistogramTest, BasicTest) {
+  std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(0, snapshot->TotalCount());
+  EXPECT_EQ(0, snapshot->sum());
+
+  histogram->Add(100);
+  std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+  EXPECT_EQ(1, snapshot1->TotalCount());
+  EXPECT_EQ(1, snapshot1->GetCount(100));
+
+  histogram->Add(100);
+  histogram->Add(101);
+  std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(3, snapshot2->TotalCount());
+  EXPECT_EQ(2, snapshot2->GetCount(100));
+  EXPECT_EQ(1, snapshot2->GetCount(101));
+}
+
+TEST_P(SparseHistogramTest, BasicTestAddCount) {
+  std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(0, snapshot->TotalCount());
+  EXPECT_EQ(0, snapshot->sum());
+
+  histogram->AddCount(100, 15);
+  std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+  EXPECT_EQ(15, snapshot1->TotalCount());
+  EXPECT_EQ(15, snapshot1->GetCount(100));
+
+  histogram->AddCount(100, 15);
+  histogram->AddCount(101, 25);
+  std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(55, snapshot2->TotalCount());
+  EXPECT_EQ(30, snapshot2->GetCount(100));
+  EXPECT_EQ(25, snapshot2->GetCount(101));
+}
+
+TEST_P(SparseHistogramTest, AddCount_LargeValuesDontOverflow) {
+  std::unique_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  std::unique_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(0, snapshot->TotalCount());
+  EXPECT_EQ(0, snapshot->sum());
+
+  histogram->AddCount(1000000000, 15);
+  std::unique_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+  EXPECT_EQ(15, snapshot1->TotalCount());
+  EXPECT_EQ(15, snapshot1->GetCount(1000000000));
+
+  histogram->AddCount(1000000000, 15);
+  histogram->AddCount(1010000000, 25);
+  std::unique_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(55, snapshot2->TotalCount());
+  EXPECT_EQ(30, snapshot2->GetCount(1000000000));
+  EXPECT_EQ(25, snapshot2->GetCount(1010000000));
+  EXPECT_EQ(55250000000LL, snapshot2->sum());
+}
+
+TEST_P(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 |
+          (use_persistent_histogram_allocator_ ? HistogramBase::kIsPersistent
+                                               : 0),
+      sparse_histogram->flags());
+
+  std::unique_ptr<HistogramSamples> samples =
+      sparse_histogram->SnapshotSamples();
+  EXPECT_EQ(3, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCount(100));
+  EXPECT_EQ(1, samples->GetCount(200));
+}
+
+TEST_P(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_P(SparseHistogramTest, Serialize) {
+  std::unique_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));
+}
+
+// Ensure that race conditions that cause multiple, identical sparse histograms
+// to be created will safely resolve to a single one.
+TEST_P(SparseHistogramTest, DuplicationSafety) {
+  const char histogram_name[] = "Duplicated";
+  size_t histogram_count = StatisticsRecorder::GetHistogramCount();
+
+  // Create a histogram that we will later duplicate.
+  HistogramBase* original =
+      SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags);
+  ++histogram_count;
+  DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount());
+  original->Add(1);
+
+  // Create a duplicate. This has to happen differently depending on where the
+  // memory is taken from.
+  if (use_persistent_histogram_allocator_) {
+    // To allocate from persistent memory, clear the last_created reference in
+    // the GlobalHistogramAllocator. This will cause an Import to recreate
+    // the just-created histogram which will then be released as a duplicate.
+    GlobalHistogramAllocator::Get()->ClearLastCreatedReferenceForTesting();
+    // Creating a different histogram will first do an Import to ensure it
+    // hasn't been created elsewhere, triggering the duplication and release.
+    SparseHistogram::FactoryGet("something.new", HistogramBase::kNoFlags);
+    ++histogram_count;
+  } else {
+    // To allocate from the heap, just call the (private) constructor directly.
+    // Delete it immediately like would have happened within FactoryGet();
+    std::unique_ptr<SparseHistogram> something =
+        NewSparseHistogram(histogram_name);
+    DCHECK_NE(original, something.get());
+  }
+  DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount());
+
+  // Re-creating the histogram via FactoryGet() will return the same one.
+  HistogramBase* duplicate =
+      SparseHistogram::FactoryGet(histogram_name, HistogramBase::kNoFlags);
+  DCHECK_EQ(original, duplicate);
+  DCHECK_EQ(histogram_count, StatisticsRecorder::GetHistogramCount());
+  duplicate->Add(2);
+
+  // Ensure that original histograms are still cross-functional.
+  original->Add(2);
+  duplicate->Add(1);
+  std::unique_ptr<HistogramSamples> snapshot_orig = original->SnapshotSamples();
+  std::unique_ptr<HistogramSamples> snapshot_dup = duplicate->SnapshotSamples();
+  DCHECK_EQ(2, snapshot_orig->GetCount(2));
+  DCHECK_EQ(2, snapshot_dup->GetCount(1));
+}
+
+TEST_P(SparseHistogramTest, FactoryTime) {
+  const int kTestCreateCount = 1 << 10;  // Must be power-of-2.
+  const int kTestLookupCount = 100000;
+  const int kTestAddCount = 100000;
+
+  // Create all histogram names in advance for accurate timing below.
+  std::vector<std::string> histogram_names;
+  for (int i = 0; i < kTestCreateCount; ++i) {
+    histogram_names.push_back(
+        StringPrintf("TestHistogram.%d", i % kTestCreateCount));
+  }
+
+  // Calculate cost of creating histograms.
+  TimeTicks create_start = TimeTicks::Now();
+  for (int i = 0; i < kTestCreateCount; ++i)
+    SparseHistogram::FactoryGet(histogram_names[i], HistogramBase::kNoFlags);
+  TimeDelta create_ticks = TimeTicks::Now() - create_start;
+  int64_t create_ms = create_ticks.InMilliseconds();
+
+  VLOG(1) << kTestCreateCount << " histogram creations took " << create_ms
+          << "ms or about "
+          << (create_ms * 1000000) / kTestCreateCount
+          << "ns each.";
+
+  // Calculate cost of looking up existing histograms.
+  TimeTicks lookup_start = TimeTicks::Now();
+  for (int i = 0; i < kTestLookupCount; ++i) {
+    // 6007 is co-prime with kTestCreateCount and so will do lookups in an
+    // order less likely to be cacheable (but still hit them all) should the
+    // underlying storage use the exact histogram name as the key.
+    const int i_mult = 6007;
+    static_assert(i_mult < INT_MAX / kTestCreateCount, "Multiplier too big");
+    int index = (i * i_mult) & (kTestCreateCount - 1);
+    SparseHistogram::FactoryGet(histogram_names[index],
+                                HistogramBase::kNoFlags);
+  }
+  TimeDelta lookup_ticks = TimeTicks::Now() - lookup_start;
+  int64_t lookup_ms = lookup_ticks.InMilliseconds();
+
+  VLOG(1) << kTestLookupCount << " histogram lookups took " << lookup_ms
+          << "ms or about "
+          << (lookup_ms * 1000000) / kTestLookupCount
+          << "ns each.";
+
+  // Calculate cost of accessing histograms.
+  HistogramBase* histogram =
+      SparseHistogram::FactoryGet(histogram_names[0], HistogramBase::kNoFlags);
+  ASSERT_TRUE(histogram);
+  TimeTicks add_start = TimeTicks::Now();
+  for (int i = 0; i < kTestAddCount; ++i)
+    histogram->Add(i & 127);
+  TimeDelta add_ticks = TimeTicks::Now() - add_start;
+  int64_t add_ms = add_ticks.InMilliseconds();
+
+  VLOG(1) << kTestAddCount << " histogram adds took " << add_ms
+          << "ms or about "
+          << (add_ms * 1000000) / kTestAddCount
+          << "ns each.";
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/statistics_recorder.cc b/libchrome/base/metrics/statistics_recorder.cc
new file mode 100644
index 0000000..42ed5a9
--- /dev/null
+++ b/libchrome/base/metrics/statistics_recorder.cc
@@ -0,0 +1,543 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <memory>
+
+#include "base/at_exit.h"
+#include "base/debug/leak_annotations.h"
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/metrics_hashes.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/stl_util.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;
+
+bool HistogramNameLesser(const base::HistogramBase* a,
+                         const base::HistogramBase* b) {
+  return a->histogram_name() < b->histogram_name();
+}
+
+}  // namespace
+
+namespace base {
+
+StatisticsRecorder::HistogramIterator::HistogramIterator(
+    const HistogramMap::iterator& iter, bool include_persistent)
+    : iter_(iter),
+      include_persistent_(include_persistent) {
+  // The starting location could point to a persistent histogram when such
+  // is not wanted. If so, skip it.
+  if (!include_persistent_ && iter_ != histograms_->end() &&
+      (iter_->second->flags() & HistogramBase::kIsPersistent)) {
+    // This operator will continue to skip until a non-persistent histogram
+    // is found.
+    operator++();
+  }
+}
+
+StatisticsRecorder::HistogramIterator::HistogramIterator(
+    const HistogramIterator& rhs)
+    : iter_(rhs.iter_),
+      include_persistent_(rhs.include_persistent_) {
+}
+
+StatisticsRecorder::HistogramIterator::~HistogramIterator() {}
+
+StatisticsRecorder::HistogramIterator&
+StatisticsRecorder::HistogramIterator::operator++() {
+  const HistogramMap::iterator histograms_end = histograms_->end();
+  if (iter_ == histograms_end || lock_ == NULL)
+    return *this;
+
+  base::AutoLock auto_lock(*lock_);
+
+  for (;;) {
+    ++iter_;
+    if (iter_ == histograms_end)
+      break;
+    if (!include_persistent_ && (iter_->second->flags() &
+                                 HistogramBase::kIsPersistent)) {
+      continue;
+    }
+    break;
+  }
+
+  return *this;
+}
+
+StatisticsRecorder::~StatisticsRecorder() {
+  DCHECK(lock_);
+  DCHECK(histograms_);
+  DCHECK(ranges_);
+
+  // Clean out what this object created and then restore what existed before.
+  Reset();
+  base::AutoLock auto_lock(*lock_);
+  histograms_ = existing_histograms_.release();
+  callbacks_ = existing_callbacks_.release();
+  ranges_ = existing_ranges_.release();
+}
+
+// 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) {
+        // The StringKey references the name within |histogram| rather than
+        // making a copy.
+        (*histograms_)[name] = histogram;
+        ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+        // If there are callbacks for this histogram, we set the kCallbackExists
+        // flag.
+        auto callback_iterator = callbacks_->find(name);
+        if (callback_iterator != callbacks_->end()) {
+          if (!callback_iterator->second.is_null())
+            histogram->SetFlags(HistogramBase::kCallbackExists);
+          else
+            histogram->ClearFlags(HistogramBase::kCallbackExists);
+        }
+        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.
+        DCHECK_EQ(histogram->histogram_name(),
+                  it->second->histogram_name()) << "hash collision";
+        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());
+  std::unique_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);
+  std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
+  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);
+  std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
+  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_) {
+    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 (auto* range_entry : *entry.second) {
+      output->push_back(range_entry);
+    }
+  }
+}
+
+// static
+HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
+  // This must be called *before* the lock is acquired below because it will
+  // call back into this object to register histograms. Those called methods
+  // will acquire the lock at that time.
+  ImportGlobalPersistentHistograms();
+
+  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;
+}
+
+// static
+StatisticsRecorder::HistogramIterator StatisticsRecorder::begin(
+    bool include_persistent) {
+  DCHECK(histograms_);
+  ImportGlobalPersistentHistograms();
+
+  HistogramMap::iterator iter_begin;
+  {
+    base::AutoLock auto_lock(*lock_);
+    iter_begin = histograms_->begin();
+  }
+  return HistogramIterator(iter_begin, include_persistent);
+}
+
+// static
+StatisticsRecorder::HistogramIterator StatisticsRecorder::end() {
+  HistogramMap::iterator iter_end;
+  {
+    base::AutoLock auto_lock(*lock_);
+    iter_end = histograms_->end();
+  }
+  return HistogramIterator(iter_end, true);
+}
+
+// static
+void StatisticsRecorder::InitLogOnShutdown() {
+  if (lock_ == nullptr)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock();
+}
+
+// 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.second->histogram_name().find(query) != std::string::npos)
+      snapshot->push_back(entry.second);
+  }
+}
+
+// static
+bool StatisticsRecorder::SetCallback(
+    const std::string& name,
+    const StatisticsRecorder::OnSampleCallback& cb) {
+  DCHECK(!cb.is_null());
+  if (lock_ == NULL)
+    return false;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return false;
+
+  if (ContainsKey(*callbacks_, name))
+    return false;
+  callbacks_->insert(std::make_pair(name, cb));
+
+  auto it = histograms_->find(name);
+  if (it != histograms_->end())
+    it->second->SetFlags(HistogramBase::kCallbackExists);
+
+  return true;
+}
+
+// static
+void StatisticsRecorder::ClearCallback(const std::string& name) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  callbacks_->erase(name);
+
+  // We also clear the flag from the histogram (if it exists).
+  auto it = histograms_->find(name);
+  if (it != histograms_->end())
+    it->second->ClearFlags(HistogramBase::kCallbackExists);
+}
+
+// static
+StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
+    const std::string& name) {
+  if (lock_ == NULL)
+    return OnSampleCallback();
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return OnSampleCallback();
+
+  auto callback_iterator = callbacks_->find(name);
+  return callback_iterator != callbacks_->end() ? callback_iterator->second
+                                                : OnSampleCallback();
+}
+
+// static
+size_t StatisticsRecorder::GetHistogramCount() {
+  if (!lock_)
+    return 0;
+
+  base::AutoLock auto_lock(*lock_);
+  if (!histograms_)
+    return 0;
+  return histograms_->size();
+}
+
+// static
+void StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) {
+  if (histograms_)
+    histograms_->erase(name);
+}
+
+// static
+std::unique_ptr<StatisticsRecorder>
+StatisticsRecorder::CreateTemporaryForTesting() {
+  return WrapUnique(new StatisticsRecorder());
+}
+
+// static
+void StatisticsRecorder::UninitializeForTesting() {
+  // Stop now if it's never been initialized.
+  if (lock_ == NULL || histograms_ == NULL)
+    return;
+
+  // Get the global instance and destruct it. It's held in static memory so
+  // can't "delete" it; call the destructor explicitly.
+  DCHECK(g_statistics_recorder_.private_instance_);
+  g_statistics_recorder_.Get().~StatisticsRecorder();
+
+  // Now the ugly part. There's no official way to release a LazyInstance once
+  // created so it's necessary to clear out an internal variable which
+  // shouldn't be publicly visible but is for initialization reasons.
+  g_statistics_recorder_.private_instance_ = 0;
+}
+
+// static
+void StatisticsRecorder::ImportGlobalPersistentHistograms() {
+  if (lock_ == NULL)
+    return;
+
+  // Import histograms from known persistent storage. Histograms could have
+  // been added by other processes and they must be fetched and recognized
+  // locally. If the persistent memory segment is not shared between processes,
+  // this call does nothing.
+  GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
+  if (allocator)
+    allocator->ImportHistogramsToStatisticsRecorder();
+}
+
+// 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() {
+  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_);
+
+  existing_histograms_.reset(histograms_);
+  existing_callbacks_.reset(callbacks_);
+  existing_ranges_.reset(ranges_);
+
+  histograms_ = new HistogramMap;
+  callbacks_ = new CallbackMap;
+  ranges_ = new RangesMap;
+
+  InitLogOnShutdownWithoutLock();
+}
+
+void StatisticsRecorder::InitLogOnShutdownWithoutLock() {
+  if (!vlog_initialized_ && VLOG_IS_ON(1)) {
+    vlog_initialized_ = true;
+    AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this);
+  }
+}
+
+// static
+void StatisticsRecorder::Reset() {
+  // If there's no lock then there is nothing to reset.
+  if (!lock_)
+    return;
+
+  std::unique_ptr<HistogramMap> histograms_deleter;
+  std::unique_ptr<CallbackMap> callbacks_deleter;
+  std::unique_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_);
+    callbacks_deleter.reset(callbacks_);
+    ranges_deleter.reset(ranges_);
+    histograms_ = NULL;
+    callbacks_ = NULL;
+    ranges_ = NULL;
+  }
+  // We are going to leak the histograms and the ranges.
+}
+
+// static
+void StatisticsRecorder::DumpHistogramsToVlog(void* /*instance*/) {
+  std::string output;
+  StatisticsRecorder::WriteGraph(std::string(), &output);
+  VLOG(1) << output;
+}
+
+
+// static
+StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
+// static
+StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL;
+// static
+StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
+// static
+base::Lock* StatisticsRecorder::lock_ = NULL;
+
+}  // namespace base
diff --git a/libchrome/base/metrics/statistics_recorder.h b/libchrome/base/metrics/statistics_recorder.h
new file mode 100644
index 0000000..c3c6ace
--- /dev/null
+++ b/libchrome/base/metrics/statistics_recorder.h
@@ -0,0 +1,243 @@
+// Copyright (c) 2012 The Chromium 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 <stdint.h>
+
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_base.h"
+#include "base/strings/string_piece.h"
+
+class SubprocessMetricsProviderTest;
+
+namespace base {
+
+class BucketRanges;
+class Lock;
+
+class BASE_EXPORT StatisticsRecorder {
+ public:
+  // A class used as a key for the histogram map below. It always references
+  // a string owned outside of this class, likely in the value of the map.
+  class StringKey : public StringPiece {
+   public:
+    // Constructs the StringKey using various sources. The source must live
+    // at least as long as the created object.
+    StringKey(const std::string& str) : StringPiece(str) {}
+    StringKey(StringPiece str) : StringPiece(str) {}
+
+    // Though StringPiece is better passed by value than by reference, in
+    // this case it's being passed many times and likely already been stored
+    // in memory (not just registers) so the benefit of pass-by-value is
+    // negated.
+    bool operator<(const StringKey& rhs) const {
+      // Since order is unimportant in the map and string comparisons can be
+      // slow, use the length as the primary sort value.
+      if (length() < rhs.length())
+        return true;
+      if (length() > rhs.length())
+        return false;
+
+      // Fall back to an actual string comparison. The lengths are the same
+      // so a simple memory-compare is sufficient. This is slightly more
+      // efficient than calling operator<() for StringPiece which would
+      // again have to check lengths before calling wordmemcmp().
+      return wordmemcmp(data(), rhs.data(), length()) < 0;
+    }
+  };
+
+  typedef std::map<StringKey, HistogramBase*> HistogramMap;
+  typedef std::vector<HistogramBase*> Histograms;
+
+  // A class for iterating over the histograms held within this global resource.
+  class BASE_EXPORT HistogramIterator {
+   public:
+    HistogramIterator(const HistogramMap::iterator& iter,
+                      bool include_persistent);
+    HistogramIterator(const HistogramIterator& rhs);  // Must be copyable.
+    ~HistogramIterator();
+
+    HistogramIterator& operator++();
+    HistogramIterator operator++(int) {
+      HistogramIterator tmp(*this);
+      operator++();
+      return tmp;
+    }
+
+    bool operator==(const HistogramIterator& rhs) const {
+      return iter_ == rhs.iter_;
+    }
+    bool operator!=(const HistogramIterator& rhs) const {
+      return iter_ != rhs.iter_;
+    }
+    HistogramBase* operator*() { return iter_->second; }
+
+   private:
+    HistogramMap::iterator iter_;
+    const bool include_persistent_;
+  };
+
+  ~StatisticsRecorder();
+
+  // 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(base::StringPiece name);
+
+  // Support for iterating over known histograms.
+  static HistogramIterator begin(bool include_persistent);
+  static HistogramIterator end();
+
+  // 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);
+
+  typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
+
+  // SetCallback sets the callback to notify when a new sample is recorded on
+  // the histogram referred to by |histogram_name|. The call to this method can
+  // be be done before or after the histogram is created. This method is thread
+  // safe. The return value is whether or not the callback was successfully set.
+  static bool SetCallback(const std::string& histogram_name,
+                          const OnSampleCallback& callback);
+
+  // ClearCallback clears any callback set on the histogram referred to by
+  // |histogram_name|. This method is thread safe.
+  static void ClearCallback(const std::string& histogram_name);
+
+  // FindCallback retrieves the callback for the histogram referred to by
+  // |histogram_name|, or a null callback if no callback exists for this
+  // histogram. This method is thread safe.
+  static OnSampleCallback FindCallback(const std::string& histogram_name);
+
+  // Returns the number of known histograms.
+  static size_t GetHistogramCount();
+
+  // Initializes logging histograms with --v=1. Safe to call multiple times.
+  // Is called from ctor but for browser it seems that it is more useful to
+  // start logging after statistics recorder, so we need to init log-on-shutdown
+  // later.
+  static void InitLogOnShutdown();
+
+  // Removes a histogram from the internal set of known ones. This can be
+  // necessary during testing persistent histograms where the underlying
+  // memory is being released.
+  static void ForgetHistogramForTesting(base::StringPiece name);
+
+  // Creates a local StatisticsRecorder object for testing purposes. All new
+  // histograms will be registered in it until it is destructed or pushed
+  // aside for the lifetime of yet another SR object. The destruction of the
+  // returned object will re-activate the previous one. Always release SR
+  // objects in the opposite order to which they're created.
+  static std::unique_ptr<StatisticsRecorder> CreateTemporaryForTesting()
+      WARN_UNUSED_RESULT;
+
+  // Resets any global instance of the statistics-recorder that was created
+  // by a call to Initialize().
+  static void UninitializeForTesting();
+
+ private:
+  // We keep a map of callbacks to histograms, so that as histograms are
+  // created, we can set the callback properly.
+  typedef std::map<std::string, OnSampleCallback> CallbackMap;
+
+  // 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_t, std::list<const BucketRanges*>*> RangesMap;
+
+  friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;
+  friend class StatisticsRecorderTest;
+
+  // Imports histograms from global persistent memory. The global lock must
+  // not be held during this call.
+  static void ImportGlobalPersistentHistograms();
+
+  // 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 the constructor to get a clean StatisticsRecorder.
+  StatisticsRecorder();
+
+  // Initialize implementation but without lock. Caller should guard
+  // StatisticsRecorder by itself if needed (it isn't in unit tests).
+  void InitLogOnShutdownWithoutLock();
+
+  // These are copies of everything that existed when the (test) Statistics-
+  // Recorder was created. The global ones have to be moved aside to create a
+  // clean environment.
+  std::unique_ptr<HistogramMap> existing_histograms_;
+  std::unique_ptr<CallbackMap> existing_callbacks_;
+  std::unique_ptr<RangesMap> existing_ranges_;
+
+  bool vlog_initialized_ = false;
+
+  static void Reset();
+  static void DumpHistogramsToVlog(void* instance);
+
+  static HistogramMap* histograms_;
+  static CallbackMap* callbacks_;
+  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/libchrome/base/metrics/statistics_recorder_unittest.cc b/libchrome/base/metrics/statistics_recorder_unittest.cc
new file mode 100644
index 0000000..65e2c98
--- /dev/null
+++ b/libchrome/base/metrics/statistics_recorder_unittest.cc
@@ -0,0 +1,659 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// 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_(logging::GetMinLogLevel()) {}
+
+  ~LogStateSaver() {
+    logging::SetMinLogLevel(old_min_log_level_);
+    logging::SetLogAssertHandler(nullptr);
+  }
+
+ private:
+  int old_min_log_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogStateSaver);
+};
+
+}  // namespace
+
+namespace base {
+
+class StatisticsRecorderTest : public testing::TestWithParam<bool> {
+ protected:
+  const int32_t kAllocatorMemorySize = 64 << 10;  // 64 KiB
+
+  StatisticsRecorderTest() : use_persistent_histogram_allocator_(GetParam()) {
+    // Get this first so it never gets created in persistent storage and will
+    // not appear in the StatisticsRecorder after it is re-initialized.
+    PersistentHistogramAllocator::GetCreateHistogramResultHistogram();
+
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+
+    // Use persistent memory for histograms if so indicated by test parameter.
+    if (use_persistent_histogram_allocator_) {
+      GlobalHistogramAllocator::CreateWithLocalMemory(
+          kAllocatorMemorySize, 0, "StatisticsRecorderTest");
+    }
+  }
+
+  ~StatisticsRecorderTest() override {
+    GlobalHistogramAllocator::ReleaseForTesting();
+    UninitializeStatisticsRecorder();
+  }
+
+  void InitializeStatisticsRecorder() {
+    DCHECK(!statistics_recorder_);
+    StatisticsRecorder::UninitializeForTesting();
+    statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    statistics_recorder_.reset();
+    StatisticsRecorder::UninitializeForTesting();
+  }
+
+  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;
+  }
+
+  int CountIterableHistograms(StatisticsRecorder::HistogramIterator* iter) {
+    int count = 0;
+    for (; *iter != StatisticsRecorder::end(); ++*iter) {
+      ++count;
+    }
+    return count;
+  }
+
+  void InitLogOnShutdown() {
+    DCHECK(statistics_recorder_);
+    statistics_recorder_->InitLogOnShutdownWithoutLock();
+  }
+
+  bool VLogInitialized() {
+    DCHECK(statistics_recorder_);
+    return statistics_recorder_->vlog_initialized_;
+  }
+
+  const bool use_persistent_histogram_allocator_;
+
+  std::unique_ptr<StatisticsRecorder> statistics_recorder_;
+  std::unique_ptr<GlobalHistogramAllocator> old_global_allocator_;
+
+ private:
+  LogStateSaver log_state_saver_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorderTest);
+};
+
+// Run all HistogramTest cases with both heap and persistent memory.
+INSTANTIATE_TEST_CASE_P(Allocator, StatisticsRecorderTest, testing::Bool());
+
+TEST_P(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_P(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_P(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_P(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_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
+
+  // Create a new global allocator using the same memory as the old one. Any
+  // old one is kept around so the memory doesn't get released.
+  old_global_allocator_ = GlobalHistogramAllocator::ReleaseForTesting();
+  if (use_persistent_histogram_allocator_) {
+    GlobalHistogramAllocator::CreateWithPersistentMemory(
+        const_cast<void*>(old_global_allocator_->data()),
+        old_global_allocator_->length(), 0, old_global_allocator_->Id(),
+        old_global_allocator_->Name());
+  }
+
+  // Reset statistics-recorder to validate operation from a clean start.
+  UninitializeStatisticsRecorder();
+  InitializeStatisticsRecorder();
+
+  if (use_persistent_histogram_allocator_) {
+    EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram1"));
+    EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram2"));
+  } else {
+    EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram1"));
+    EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram2"));
+  }
+  EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
+}
+
+TEST_P(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_P(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_P(StatisticsRecorderTest, RegisterHistogramWithMacros) {
+  // Macros cache pointers and so tests that use them can only be run once.
+  // Stop immediately if this test has run previously.
+  static bool already_run = false;
+  if (already_run)
+    return;
+  already_run = true;
+
+  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_P(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_P(StatisticsRecorderTest, ToJSON) {
+  Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(30);
+  Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(40);
+  Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(30);
+  Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(40);
+
+  std::string json(StatisticsRecorder::ToJSON(std::string()));
+
+  // Check for valid JSON.
+  std::unique_ptr<Value> root = JSONReader::Read(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 = JSONReader::Read(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());
+}
+
+TEST_P(StatisticsRecorderTest, IterationTest) {
+  Histogram::FactoryGet("IterationTest1", 1, 64, 16, HistogramBase::kNoFlags);
+  Histogram::FactoryGet("IterationTest2", 1, 64, 16, HistogramBase::kNoFlags);
+
+  StatisticsRecorder::HistogramIterator i1 = StatisticsRecorder::begin(true);
+  EXPECT_EQ(2, CountIterableHistograms(&i1));
+
+  StatisticsRecorder::HistogramIterator i2 = StatisticsRecorder::begin(false);
+  EXPECT_EQ(use_persistent_histogram_allocator_ ? 0 : 2,
+            CountIterableHistograms(&i2));
+
+  // Create a new global allocator using the same memory as the old one. Any
+  // old one is kept around so the memory doesn't get released.
+  old_global_allocator_ = GlobalHistogramAllocator::ReleaseForTesting();
+  if (use_persistent_histogram_allocator_) {
+    GlobalHistogramAllocator::CreateWithPersistentMemory(
+        const_cast<void*>(old_global_allocator_->data()),
+        old_global_allocator_->length(), 0, old_global_allocator_->Id(),
+        old_global_allocator_->Name());
+  }
+
+  // Reset statistics-recorder to validate operation from a clean start.
+  UninitializeStatisticsRecorder();
+  InitializeStatisticsRecorder();
+
+  StatisticsRecorder::HistogramIterator i3 = StatisticsRecorder::begin(true);
+  EXPECT_EQ(use_persistent_histogram_allocator_ ? 2 : 0,
+            CountIterableHistograms(&i3));
+
+  StatisticsRecorder::HistogramIterator i4 = StatisticsRecorder::begin(false);
+  EXPECT_EQ(0, CountIterableHistograms(&i4));
+}
+
+namespace {
+
+// CallbackCheckWrapper is simply a convenient way to check and store that
+// a callback was actually run.
+struct CallbackCheckWrapper {
+  CallbackCheckWrapper() : called(false), last_histogram_value(0) {}
+
+  void OnHistogramChanged(base::HistogramBase::Sample histogram_value) {
+    called = true;
+    last_histogram_value = histogram_value;
+  }
+
+  bool called;
+  base::HistogramBase::Sample last_histogram_value;
+};
+
+}  // namespace
+
+// Check that you can't overwrite the callback with another.
+TEST_P(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+
+  result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_FALSE(result);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_P(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_FALSE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  histogram->Add(1);
+
+  EXPECT_TRUE(callback_wrapper.called);
+}
+
+// Check that you can't overwrite the callback with another.
+TEST_P(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  CallbackCheckWrapper callback_wrapper;
+
+  bool result = base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+  EXPECT_TRUE(result);
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists,
+            base::HistogramBase::kCallbackExists);
+
+  base::StatisticsRecorder::ClearCallback("TestHistogram");
+  EXPECT_EQ(histogram->flags() & base::HistogramBase::kCallbackExists, 0);
+
+  histogram->Add(1);
+
+  EXPECT_FALSE(callback_wrapper.called);
+}
+
+// Check that callback is used.
+TEST_P(StatisticsRecorderTest, CallbackUsedTest) {
+  {
+    HistogramBase* histogram = Histogram::FactoryGet(
+        "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+    EXPECT_TRUE(histogram);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                    base::Unretained(&callback_wrapper)));
+
+    histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+        "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestLinearHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    linear_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    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);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestCustomHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    custom_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+
+  {
+    HistogramBase* custom_histogram = SparseHistogram::FactoryGet(
+        "TestSparseHistogram", HistogramBase::kNoFlags);
+
+    CallbackCheckWrapper callback_wrapper;
+
+    base::StatisticsRecorder::SetCallback(
+        "TestSparseHistogram",
+        base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                   base::Unretained(&callback_wrapper)));
+
+    custom_histogram->Add(1);
+
+    EXPECT_TRUE(callback_wrapper.called);
+    EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+  }
+}
+
+// Check that setting a callback before the histogram exists works.
+TEST_P(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
+  CallbackCheckWrapper callback_wrapper;
+
+  base::StatisticsRecorder::SetCallback(
+      "TestHistogram", base::Bind(&CallbackCheckWrapper::OnHistogramChanged,
+                                  base::Unretained(&callback_wrapper)));
+
+  HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
+                                                   HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+  histogram->Add(1);
+
+  EXPECT_TRUE(callback_wrapper.called);
+  EXPECT_EQ(callback_wrapper.last_histogram_value, 1);
+}
+
+TEST_P(StatisticsRecorderTest, LogOnShutdownNotInitialized) {
+  UninitializeStatisticsRecorder();
+  logging::SetMinLogLevel(logging::LOG_WARNING);
+  InitializeStatisticsRecorder();
+  EXPECT_FALSE(VLOG_IS_ON(1));
+  EXPECT_FALSE(VLogInitialized());
+  InitLogOnShutdown();
+  EXPECT_FALSE(VLogInitialized());
+}
+
+TEST_P(StatisticsRecorderTest, LogOnShutdownInitializedExplicitly) {
+  UninitializeStatisticsRecorder();
+  logging::SetMinLogLevel(logging::LOG_WARNING);
+  InitializeStatisticsRecorder();
+  EXPECT_FALSE(VLOG_IS_ON(1));
+  EXPECT_FALSE(VLogInitialized());
+  logging::SetMinLogLevel(logging::LOG_VERBOSE);
+  EXPECT_TRUE(VLOG_IS_ON(1));
+  InitLogOnShutdown();
+  EXPECT_TRUE(VLogInitialized());
+}
+
+TEST_P(StatisticsRecorderTest, LogOnShutdownInitialized) {
+  UninitializeStatisticsRecorder();
+  logging::SetMinLogLevel(logging::LOG_VERBOSE);
+  InitializeStatisticsRecorder();
+  EXPECT_TRUE(VLOG_IS_ON(1));
+  EXPECT_TRUE(VLogInitialized());
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/user_metrics.cc b/libchrome/base/metrics/user_metrics.cc
new file mode 100644
index 0000000..169a063
--- /dev/null
+++ b/libchrome/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 <stddef.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+namespace {
+
+LazyInstance<std::vector<ActionCallback>> g_callbacks =
+    LAZY_INSTANCE_INITIALIZER;
+LazyInstance<scoped_refptr<SingleThreadTaskRunner>> g_task_runner =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+void RecordAction(const UserMetricsAction& action) {
+  RecordComputedAction(action.str_);
+}
+
+void RecordComputedAction(const std::string& action) {
+  if (!g_task_runner.Get()) {
+    DCHECK(g_callbacks.Get().empty());
+    return;
+  }
+
+  if (!g_task_runner.Get()->BelongsToCurrentThread()) {
+    g_task_runner.Get()->PostTask(FROM_HERE,
+                                  Bind(&RecordComputedAction, action));
+    return;
+  }
+
+  for (const ActionCallback& callback : g_callbacks.Get()) {
+    callback.Run(action);
+  }
+}
+
+void AddActionCallback(const ActionCallback& callback) {
+  // Only allow adding a callback if the task runner is set.
+  DCHECK(g_task_runner.Get());
+  DCHECK(g_task_runner.Get()->BelongsToCurrentThread());
+  g_callbacks.Get().push_back(callback);
+}
+
+void RemoveActionCallback(const ActionCallback& callback) {
+  DCHECK(g_task_runner.Get());
+  DCHECK(g_task_runner.Get()->BelongsToCurrentThread());
+  std::vector<ActionCallback>* callbacks = g_callbacks.Pointer();
+  for (size_t i = 0; i < callbacks->size(); ++i) {
+    if ((*callbacks)[i].Equals(callback)) {
+      callbacks->erase(callbacks->begin() + i);
+      return;
+    }
+  }
+}
+
+void SetRecordActionTaskRunner(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  DCHECK(task_runner->BelongsToCurrentThread());
+  DCHECK(!g_task_runner.Get() || g_task_runner.Get()->BelongsToCurrentThread());
+  g_task_runner.Get() = task_runner;
+}
+
+}  // namespace base
diff --git a/libchrome/base/metrics/user_metrics.h b/libchrome/base/metrics/user_metrics.h
new file mode 100644
index 0000000..93701e8
--- /dev/null
+++ b/libchrome/base/metrics/user_metrics.h
@@ -0,0 +1,70 @@
+// 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"
+#include "base/single_thread_task_runner.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 function must be called after the task runner has been set with
+// SetRecordActionTaskRunner().
+//
+// "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 should be followed by a
+// string literal parameter and not a variable e.g.
+//   RecordAction(UserMetricsAction("my 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.
+// This function must be called after the task runner has been set with
+// SetRecordActionTaskRunner().
+BASE_EXPORT void RecordComputedAction(const std::string& action);
+
+// Called with the action string.
+typedef Callback<void(const std::string&)> ActionCallback;
+
+// Add/remove action callbacks (see above).
+// These functions must be called after the task runner has been set with
+// SetRecordActionTaskRunner().
+BASE_EXPORT void AddActionCallback(const ActionCallback& callback);
+BASE_EXPORT void RemoveActionCallback(const ActionCallback& callback);
+
+// Set the task runner on which to record actions.
+BASE_EXPORT void SetRecordActionTaskRunner(
+    scoped_refptr<SingleThreadTaskRunner> task_runner);
+
+}  // namespace base
+
+#endif  // BASE_METRICS_USER_METRICS_H_
diff --git a/libchrome/base/metrics/user_metrics_action.h b/libchrome/base/metrics/user_metrics_action.h
new file mode 100644
index 0000000..3eca3dd
--- /dev/null
+++ b/libchrome/base/metrics/user_metrics_action.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_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 you should use a string literal
+// parameter e.g.
+//   RecordAction(UserMetricsAction("my 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.
+// 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/libchrome/base/native_library.h b/libchrome/base/native_library.h
new file mode 100644
index 0000000..b4f3a3c
--- /dev/null
+++ b/libchrome/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/strings/string_piece.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)
+using NativeLibrary = HMODULE;
+#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;
+  };
+};
+using NativeLibrary = NativeLibraryStruct*;
+#elif defined(OS_POSIX)
+using NativeLibrary = void*;
+#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,
+                                                      StringPiece name);
+
+// Returns the full platform specific name for a native library.
+// |name| must be ASCII.
+// For example:
+// "mylib" returns "mylib.dll" on Windows, "libmylib.so" on Linux,
+// "libmylib.dylib" on Mac.
+BASE_EXPORT std::string GetNativeLibraryName(StringPiece name);
+
+}  // namespace base
+
+#endif  // BASE_NATIVE_LIBRARY_H_
diff --git a/libchrome/base/native_library_posix.cc b/libchrome/base/native_library_posix.cc
new file mode 100644
index 0000000..2dc434b
--- /dev/null
+++ b/libchrome/base/native_library_posix.cc
@@ -0,0 +1,59 @@
+// 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/string_util.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.
+  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,
+                                          StringPiece name) {
+  return dlsym(library, name.data());
+}
+
+// static
+std::string GetNativeLibraryName(StringPiece name) {
+  DCHECK(IsStringASCII(name));
+  return "lib" + name.as_string() + ".so";
+}
+
+}  // namespace base
diff --git a/libchrome/base/numerics/OWNERS b/libchrome/base/numerics/OWNERS
new file mode 100644
index 0000000..41f35fc
--- /dev/null
+++ b/libchrome/base/numerics/OWNERS
@@ -0,0 +1,3 @@
+jschuh@chromium.org
+tsepez@chromium.org
+
diff --git a/libchrome/base/numerics/safe_conversions.h b/libchrome/base/numerics/safe_conversions.h
new file mode 100644
index 0000000..6b558af
--- /dev/null
+++ b/libchrome/base/numerics/safe_conversions.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.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
+
+#include <stddef.h>
+
+#include <limits>
+#include <type_traits>
+
+#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>
+constexpr bool IsValueInRangeForNumericType(Src value) {
+  return internal::DstRangeRelationToSrcRange<Dst>(value) ==
+         internal::RANGE_VALID;
+}
+
+// Convenience function for determining if a numeric value is negative without
+// throwing compiler warnings on: unsigned(value) < 0.
+template <typename T>
+constexpr typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
+IsValueNegative(T value) {
+  static_assert(std::numeric_limits<T>::is_specialized,
+                "Argument must be numeric.");
+  return value < 0;
+}
+
+template <typename T>
+constexpr typename std::enable_if<!std::numeric_limits<T>::is_signed,
+                                  bool>::type IsValueNegative(T) {
+  static_assert(std::numeric_limits<T>::is_specialized,
+                "Argument must be numeric.");
+  return false;
+}
+
+// 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);
+}
+
+// HandleNaN will cause this class to CHECK(false).
+struct SaturatedCastNaNBehaviorCheck {
+  template <typename T>
+  static T HandleNaN() {
+    CHECK(false);
+    return T();
+  }
+};
+
+// HandleNaN will return 0 in this case.
+struct SaturatedCastNaNBehaviorReturnZero {
+  template <typename T>
+  static constexpr T HandleNaN() {
+    return T();
+  }
+};
+
+namespace internal {
+// This wrapper is used for C++11 constexpr support by avoiding the declaration
+// of local variables in the saturated_cast template function.
+template <typename Dst, class NaNHandler, typename Src>
+constexpr Dst saturated_cast_impl(const Src value,
+                                  const RangeConstraint constraint) {
+  return constraint == RANGE_VALID
+             ? static_cast<Dst>(value)
+             : (constraint == RANGE_UNDERFLOW
+                    ? std::numeric_limits<Dst>::min()
+                    : (constraint == RANGE_OVERFLOW
+                           ? std::numeric_limits<Dst>::max()
+                           : (constraint == RANGE_INVALID
+                                  ? NaNHandler::template HandleNaN<Dst>()
+                                  : (NOTREACHED(), static_cast<Dst>(value)))));
+}
+}  // namespace internal
+
+// 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 defer the behavior to a
+// specified class. By default, it will return 0.
+template <typename Dst,
+          class NaNHandler = SaturatedCastNaNBehaviorReturnZero,
+          typename Src>
+constexpr Dst saturated_cast(Src value) {
+  return std::numeric_limits<Dst>::is_iec559
+             ? static_cast<Dst>(value)  // Floating point optimization.
+             : internal::saturated_cast_impl<Dst, NaNHandler>(
+                   value, internal::DstRangeRelationToSrcRange<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>
+constexpr 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 the actual value being assigned.
+template <typename T>
+class StrictNumeric {
+ public:
+  typedef T type;
+
+  constexpr StrictNumeric() : value_(0) {}
+
+  // Copy constructor.
+  template <typename Src>
+  constexpr 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>
+  constexpr StrictNumeric(Src value)
+      : value_(strict_cast<T>(value)) {}
+
+  // The numeric cast operator basically handles all the magic.
+  template <typename Dst>
+  constexpr operator Dst() const {
+    return strict_cast<Dst>(value_);
+  }
+
+ private:
+  const 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/libchrome/base/numerics/safe_conversions_impl.h b/libchrome/base/numerics/safe_conversions_impl.h
new file mode 100644
index 0000000..0f0aebc
--- /dev/null
+++ b/libchrome/base/numerics/safe_conversions_impl.h
@@ -0,0 +1,265 @@
+// 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.h>
+#include <stdint.h>
+
+#include <climits>
+#include <limits>
+
+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_assert(std::is_arithmetic<NumericType>::value,
+                "Argument must be numeric.");
+  static const int value = std::numeric_limits<NumericType>::is_iec559
+                               ? std::numeric_limits<NumericType>::max_exponent
+                               : (sizeof(NumericType) * CHAR_BIT + 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.
+constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint) {
+  // TODO(jschuh): Once we get full C++14 support we want this
+  // assert(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.
+constexpr 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));
+}
+
+// The following helper template addresses a corner case in range checks for
+// conversion from a floating-point type to an integral type of smaller range
+// but larger precision (e.g. float -> unsigned). The problem is as follows:
+//   1. Integral maximum is always one less than a power of two, so it must be
+//      truncated to fit the mantissa of the floating point. The direction of
+//      rounding is implementation defined, but by default it's always IEEE
+//      floats, which round to nearest and thus result in a value of larger
+//      magnitude than the integral value.
+//      Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
+//                                   // is 4294967295u.
+//   2. If the floating point value is equal to the promoted integral maximum
+//      value, a range check will erroneously pass.
+//      Example: (4294967296f <= 4294967295u) // This is true due to a precision
+//                                            // loss in rounding up to float.
+//   3. When the floating point value is then converted to an integral, the
+//      resulting value is out of range for the target integral type and
+//      thus is implementation defined.
+//      Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
+// To fix this bug we manually truncate the maximum value when the destination
+// type is an integral of larger precision than the source floating-point type,
+// such that the resulting maximum is represented exactly as a floating point.
+template <typename Dst, typename Src>
+struct NarrowingRange {
+  typedef typename std::numeric_limits<Src> SrcLimits;
+  typedef typename std::numeric_limits<Dst> DstLimits;
+  // The following logic avoids warnings where the max function is
+  // instantiated with invalid values for a bit shift (even though
+  // such a function can never be called).
+  static const int shift = (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
+                            SrcLimits::digits < DstLimits::digits &&
+                            SrcLimits::is_iec559 &&
+                            DstLimits::is_integer)
+                               ? (DstLimits::digits - SrcLimits::digits)
+                               : 0;
+
+  static constexpr Dst max() {
+    // We use UINTMAX_C below to avoid compiler warnings about shifting floating
+    // points. Since it's a compile time calculation, it shouldn't have any
+    // performance impact.
+    return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1);
+  }
+
+  static constexpr Dst min() {
+    return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max()
+                                               : DstLimits::min();
+  }
+};
+
+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 constexpr 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 constexpr RangeConstraint Check(Src value) {
+    return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
+                              (value >= NarrowingRange<Dst, Src>::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 constexpr RangeConstraint Check(Src value) {
+    return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::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 constexpr RangeConstraint Check(Src value) {
+    return sizeof(Dst) > sizeof(Src)
+               ? RANGE_VALID
+               : GetRangeConstraint(
+                     value <= static_cast<Src>(NarrowingRange<Dst, Src>::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 constexpr RangeConstraint Check(Src value) {
+    return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
+               ? GetRangeConstraint(true, value >= static_cast<Src>(0))
+               : GetRangeConstraint(
+                     value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()),
+                     value >= static_cast<Src>(0));
+  }
+};
+
+template <typename Dst, typename Src>
+constexpr 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/libchrome/base/numerics/safe_math.h b/libchrome/base/numerics/safe_math.h
new file mode 100644
index 0000000..d0003b7
--- /dev/null
+++ b/libchrome/base/numerics/safe_math.h
@@ -0,0 +1,309 @@
+// 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 <stddef.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "base/logging.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 = untrusted_input_value;
+//   checked_size += HEADER LENGTH;
+//   if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
+//     Do stuff...
+template <typename T>
+class CheckedNumeric {
+  static_assert(std::is_arithmetic<T>::value,
+                "CheckedNumeric<T>: T must be a numeric type.");
+
+ 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)  // NOLINT(runtime/explicit)
+      : 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)  // NOLINT(runtime/explicit)
+      : 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);
+  }
+
+  // This function is available only for integral types. It returns an unsigned
+  // integer of the same width as the source type, containing the absolute value
+  // of the source, and properly handling signed min.
+  CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const {
+    return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
+        CheckedUnsignedAbs(state_.value()), state_.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 std::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 std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) {
+    return u;
+  }
+
+  static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
+
+ private:
+  template <typename NumericType>
+  struct UnderlyingType {
+    using type = NumericType;
+  };
+
+  template <typename NumericType>
+  struct UnderlyingType<CheckedNumeric<NumericType>> {
+    using type = NumericType;
+  };
+
+  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<typename UnderlyingType<Src>::type>::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,                                         \
+            typename std::enable_if<std::is_arithmetic<Src>::value>::type* =  \
+                nullptr>                                                      \
+  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 left numeric and right CheckedNumeric. */ \
+  template <typename T, typename Src,                                         \
+            typename std::enable_if<std::is_arithmetic<Src>::value>::type* =  \
+                nullptr>                                                      \
+  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/libchrome/base/numerics/safe_math_impl.h b/libchrome/base/numerics/safe_math_impl.h
new file mode 100644
index 0000000..f214f3f
--- /dev/null
+++ b/libchrome/base/numerics/safe_math_impl.h
@@ -0,0 +1,532 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions.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 std::enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
+};
+
+template <typename Integer>
+struct SignedIntegerForSize {
+  typedef typename std::enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
+};
+
+template <typename Integer>
+struct TwiceWiderInteger {
+  typedef typename std::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 std::enable_if<std::numeric_limits<Integer>::is_integer,
+                                       size_t>::type value =
+      CHAR_BIT * sizeof(Integer) - 1;
+};
+
+// This is used for UnsignedAbs, where we need to support floating-point
+// template instantiations even though we don't actually support the operations.
+// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
+// so the float versions will not compile.
+template <typename Numeric,
+          bool IsInteger = std::numeric_limits<Numeric>::is_integer,
+          bool IsFloat = std::numeric_limits<Numeric>::is_iec559>
+struct UnsignedOrFloatForSize;
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, true, false> {
+  typedef typename UnsignedIntegerForSize<Numeric>::type type;
+};
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, false, true> {
+  typedef Numeric type;
+};
+
+// Helper templates for integer manipulations.
+
+template <typename T>
+constexpr 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>
+constexpr T BinaryComplement(T x) {
+  return static_cast<T>(~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 std::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 = static_cast<UnsignedDst>(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(
+            static_cast<UnsignedDst>((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 std::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 = static_cast<UnsignedDst>(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(
+            static_cast<UnsignedDst>((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 std::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 std::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) {
+    *validity = RANGE_VALID;
+    return static_cast<T>(0);
+
+  } 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 static_cast<T>(x * y);
+}
+
+template <typename T>
+typename std::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 static_cast<T>(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 std::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 static_cast<T>(x / y);
+}
+
+template <typename T>
+typename std::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 static_cast<T>(x % y);
+}
+
+template <typename T>
+typename std::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 static_cast<T>(x % y);
+}
+
+template <typename T>
+typename std::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 static_cast<T>(-value);
+}
+
+template <typename T>
+typename std::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 std::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 std::enable_if<std::numeric_limits<T>::is_integer &&
+                            !std::numeric_limits<T>::is_signed,
+                        T>::type
+CheckedAbs(T value, RangeConstraint* validity) {
+  // T is unsigned, so |value| must already be positive.
+  *validity = RANGE_VALID;
+  return value;
+}
+
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            std::numeric_limits<T>::is_signed,
+                        typename UnsignedIntegerForSize<T>::type>::type
+CheckedUnsignedAbs(T value) {
+  typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
+  return value == std::numeric_limits<T>::min()
+             ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
+             : static_cast<UnsignedT>(std::abs(value));
+}
+
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+                            !std::numeric_limits<T>::is_signed,
+                        T>::type
+CheckedUnsignedAbs(T value) {
+  // T is unsigned, so |value| must already be positive.
+  return static_cast<T>(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 std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
+      Checked##NAME(T, T, RangeConstraint*) {                         \
+    NOTREACHED();                                                     \
+    return static_cast<T>(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 std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
+    T value,
+    RangeConstraint*) {
+  return static_cast<T>(-value);
+}
+
+template <typename T>
+typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
+    T value,
+    RangeConstraint*) {
+  return static_cast<T>(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_ : CHAR_BIT;  // Actually requires only two bits.
+
+ 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 std::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 std::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 std::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 have the type
+// with the larger maximum exponent take precedence.
+enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION };
+
+template <typename Lhs,
+          typename Rhs = Lhs,
+          ArithmeticPromotionCategory Promotion =
+              (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
+                  ? LEFT_PROMOTION
+                  : RIGHT_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;
+};
+
+// 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/libchrome/base/numerics/safe_numerics_unittest.cc b/libchrome/base/numerics/safe_numerics_unittest.cc
new file mode 100644
index 0000000..4be7ab5
--- /dev/null
+++ b/libchrome/base/numerics/safe_numerics_unittest.cc
@@ -0,0 +1,762 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "base/compiler_specific.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
+#include <mmintrin.h>
+#endif
+
+using std::numeric_limits;
+using base::CheckedNumeric;
+using base::checked_cast;
+using base::IsValueInRangeForNumericType;
+using base::IsValueNegative;
+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::internal::SignedIntegerForSize;
+
+// 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
+
+// This is a helper function for finding the maximum value in Src that can be
+// wholy represented as the destination floating-point type.
+template <typename Dst, typename Src>
+Dst GetMaxConvertibleToFloat() {
+  typedef numeric_limits<Dst> DstLimits;
+  typedef numeric_limits<Src> SrcLimits;
+  static_assert(SrcLimits::is_specialized, "Source must be numeric.");
+  static_assert(DstLimits::is_specialized, "Destination must be numeric.");
+  CHECK(DstLimits::is_iec559);
+
+  if (SrcLimits::digits <= DstLimits::digits &&
+      MaxExponent<Src>::value <= MaxExponent<Dst>::value)
+    return SrcLimits::max();
+  Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0);
+  while (max != static_cast<Src>(static_cast<Dst>(max))) {
+    max /= 2;
+  }
+  return static_cast<Dst>(max);
+}
+
+// Helper macros to wrap displaying the conversion types and line numbers.
+#define TEST_EXPECTED_VALIDITY(expected, actual)                           \
+  EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).IsValid())               \
+      << "Result test: Value " << +(actual).ValueUnsafe() << " as " << dst \
+      << " on line " << line;
+
+#define TEST_EXPECTED_SUCCESS(actual) TEST_EXPECTED_VALIDITY(true, actual)
+#define TEST_EXPECTED_FAILURE(actual) TEST_EXPECTED_VALIDITY(false, actual)
+
+#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 std::enable_if<numeric_limits<Dst>::is_integer &&
+                                numeric_limits<Dst>::is_signed,
+                            int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_FAILURE(-CheckedNumeric<Dst>(DstLimits::min()));
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
+
+  TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + -1);
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) +
+                        -DstLimits::max());
+
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) - 1);
+  TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) - -1);
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) -
+                        -DstLimits::max());
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) -
+                        DstLimits::max());
+
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) * 2);
+
+  TEST_EXPECTED_FAILURE(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_FAILURE(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 std::enable_if<numeric_limits<Dst>::is_integer &&
+                                !numeric_limits<Dst>::is_signed,
+                            int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::min()));
+  TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) - 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2);
+  TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).UnsignedAbs());
+  TEST_EXPECTED_SUCCESS(
+      CheckedNumeric<typename SignedIntegerForSize<Dst>::type>(
+          std::numeric_limits<typename SignedIntegerForSize<Dst>::type>::min())
+          .UnsignedAbs());
+
+  // 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 std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::min()));
+
+  TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
+
+  TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + 1);
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) +
+                        -DstLimits::max());
+
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) -
+                        -DstLimits::max());
+  TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) -
+                        DstLimits::max());
+
+  TEST_EXPECTED_SUCCESS(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_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) + 1);
+  TEST_EXPECTED_FAILURE(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_SUCCESS(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_FAILURE(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_SUCCESS(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_SUCCESS(SrcLimits::max() * checked_dst);
+
+      } else {  // Larger, but not at least twice as large.
+        TEST_EXPECTED_FAILURE(SrcLimits::max() * checked_dst);
+        TEST_EXPECTED_SUCCESS(checked_dst + 1);
+      }
+    } else {  // Same width type.
+      TEST_EXPECTED_FAILURE(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_FAILURE(checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_FAILURE(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());
+      if (DstLimits::is_integer) {
+        if (SrcLimits::digits < DstLimits::digits) {
+          TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+                              static_cast<Src>(DstLimits::max()));
+        } else {
+          TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+        }
+        TEST_EXPECTED_RANGE(
+            RANGE_VALID,
+            static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+        TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+      }
+    } 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_FAILURE(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_FAILURE(checked_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_FAILURE(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_FAILURE(checked_dst + SrcLimits::max());
+    TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_FAILURE(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());
+      if (DstLimits::is_integer) {
+        if (SrcLimits::digits < DstLimits::digits) {
+          TEST_EXPECTED_RANGE(RANGE_OVERFLOW,
+                              static_cast<Src>(DstLimits::max()));
+        } else {
+          TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max()));
+        }
+        TEST_EXPECTED_RANGE(
+            RANGE_VALID,
+            static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>()));
+        TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min()));
+      }
+    } 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_FAILURE(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());
+
+  EXPECT_TRUE(IsValueNegative(-1));
+  EXPECT_TRUE(IsValueNegative(numeric_limits<int>::min()));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::min()));
+  EXPECT_TRUE(IsValueNegative(-numeric_limits<double>::max()));
+  EXPECT_FALSE(IsValueNegative(0));
+  EXPECT_FALSE(IsValueNegative(1));
+  EXPECT_FALSE(IsValueNegative(0u));
+  EXPECT_FALSE(IsValueNegative(1u));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<int>::max()));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::max()));
+  EXPECT_FALSE(IsValueNegative(numeric_limits<double>::max()));
+
+  // 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));
+
+  float not_a_number = std::numeric_limits<float>::infinity() -
+                       std::numeric_limits<float>::infinity();
+  EXPECT_TRUE(std::isnan(not_a_number));
+  EXPECT_EQ(0, saturated_cast<int>(not_a_number));
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+TEST(SafeNumerics, SaturatedCastChecks) {
+  float not_a_number = std::numeric_limits<float>::infinity() -
+                       std::numeric_limits<float>::infinity();
+  EXPECT_TRUE(std::isnan(not_a_number));
+  EXPECT_DEATH((saturated_cast<int, base::SaturatedCastNaNBehaviorCheck>(
+      not_a_number)), "");
+}
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+TEST(SafeNumerics, IsValueInRangeForNumericType) {
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(2));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0xffffffff)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffff));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffffu));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0x80000000u));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0xffffffffu));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x80000000)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(
+      static_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+      static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1));
+  EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(2));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0xffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1)));
+  EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(
+      std::numeric_limits<int64_t>::min()));
+
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(-1));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffff));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x80000000u));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0xffffffffu));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x80000000)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0xffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x100000000)));
+  EXPECT_TRUE(
+      IsValueInRangeForNumericType<int64_t>(INT64_C(0x7fffffffffffffff)));
+  EXPECT_TRUE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0x7fffffffffffffff)));
+  EXPECT_FALSE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0x8000000000000000)));
+  EXPECT_FALSE(
+      IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff)));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      std::numeric_limits<int32_t>::min()));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      static_cast<int64_t>(std::numeric_limits<int32_t>::min())));
+  EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(
+      std::numeric_limits<int64_t>::min()));
+}
+
+TEST(SafeNumerics, CompoundNumericOperations) {
+  CheckedNumeric<int> a = 1;
+  CheckedNumeric<int> b = 2;
+  CheckedNumeric<int> c = 3;
+  CheckedNumeric<int> d = 4;
+  a += b;
+  EXPECT_EQ(3, a.ValueOrDie());
+  a -= c;
+  EXPECT_EQ(0, a.ValueOrDie());
+  d /= b;
+  EXPECT_EQ(2, d.ValueOrDie());
+  d *= d;
+  EXPECT_EQ(4, d.ValueOrDie());
+
+  CheckedNumeric<int> too_large = std::numeric_limits<int>::max();
+  EXPECT_TRUE(too_large.IsValid());
+  too_large += d;
+  EXPECT_FALSE(too_large.IsValid());
+  too_large -= d;
+  EXPECT_FALSE(too_large.IsValid());
+  too_large /= d;
+  EXPECT_FALSE(too_large.IsValid());
+}
diff --git a/libchrome/base/observer_list.h b/libchrome/base/observer_list.h
new file mode 100644
index 0000000..afe1f46
--- /dev/null
+++ b/libchrome/base/observer_list.h
@@ -0,0 +1,249 @@
+// 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 <stddef.h>
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/stl_util.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 (ContainsValue(observers_, obs)) {
+    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()) {                        \
+      typename 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/libchrome/base/observer_list_threadsafe.h b/libchrome/base/observer_list_threadsafe.h
new file mode 100644
index 0000000..fe78354
--- /dev/null
+++ b/libchrome/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 <tuple>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.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/threading/platform_thread.h"
+#include "base/threading/thread_task_runner_handle.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) {
+    static_assert((internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+                  "bad unbound method params");
+  }
+  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, std::tuple<Params...>> method(
+        m, std::make_tuple(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, std::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/libchrome/base/observer_list_unittest.cc b/libchrome/base/observer_list_unittest.cc
new file mode 100644
index 0000000..097a2ed
--- /dev/null
+++ b/libchrome/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()));
+    RunLoop().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/libchrome/base/optional.h b/libchrome/base/optional.h
new file mode 100644
index 0000000..b468964
--- /dev/null
+++ b/libchrome/base/optional.h
@@ -0,0 +1,457 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OPTIONAL_H_
+#define BASE_OPTIONAL_H_
+
+#include <type_traits>
+
+#include "base/logging.h"
+#include "base/memory/aligned_memory.h"
+#include "base/template_util.h"
+
+namespace base {
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/in_place_t
+struct in_place_t {};
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
+struct nullopt_t {
+  constexpr explicit nullopt_t(int) {}
+};
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/in_place
+constexpr in_place_t in_place = {};
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/nullopt
+constexpr nullopt_t nullopt(0);
+
+namespace internal {
+
+template <typename T, bool = base::is_trivially_destructible<T>::value>
+struct OptionalStorage {
+  // When T is not trivially destructible we must call its
+  // destructor before deallocating its memory.
+  ~OptionalStorage() {
+    if (!is_null_)
+      buffer_.template data_as<T>()->~T();
+  }
+
+  bool is_null_ = true;
+  base::AlignedMemory<sizeof(T), ALIGNOF(T)> buffer_;
+};
+
+template <typename T>
+struct OptionalStorage<T, true> {
+  // When T is trivially destructible (i.e. its destructor does nothing)
+  // there is no need to call it.
+  // Since |base::AlignedMemory| is just an array its destructor
+  // is trivial. Explicitly defaulting the destructor means it's not
+  // user-provided. All of this together make this destructor trivial.
+  ~OptionalStorage() = default;
+
+  bool is_null_ = true;
+  base::AlignedMemory<sizeof(T), ALIGNOF(T)> buffer_;
+};
+
+}  // namespace internal
+
+// base::Optional is a Chromium version of the C++17 optional class:
+// std::optional documentation:
+// http://en.cppreference.com/w/cpp/utility/optional
+// Chromium documentation:
+// https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
+//
+// These are the differences between the specification and the implementation:
+// - The constructor and emplace method using initializer_list are not
+//   implemented because 'initializer_list' is banned from Chromium.
+// - Constructors do not use 'constexpr' as it is a C++14 extension.
+// - 'constexpr' might be missing in some places for reasons specified locally.
+// - No exceptions are thrown, because they are banned from Chromium.
+// - All the non-members are in the 'base' namespace instead of 'std'.
+template <typename T>
+class Optional {
+ public:
+  using value_type = T;
+
+  constexpr Optional() = default;
+  Optional(base::nullopt_t) : Optional() {}
+
+  Optional(const Optional& other) {
+    if (!other.storage_.is_null_)
+      Init(other.value());
+  }
+
+  Optional(Optional&& other) {
+    if (!other.storage_.is_null_)
+      Init(std::move(other.value()));
+  }
+
+  Optional(const T& value) { Init(value); }
+
+  Optional(T&& value) { Init(std::move(value)); }
+
+  template <class... Args>
+  explicit Optional(base::in_place_t, Args&&... args) {
+    emplace(std::forward<Args>(args)...);
+  }
+
+  ~Optional() = default;
+
+  Optional& operator=(base::nullopt_t) {
+    FreeIfNeeded();
+    return *this;
+  }
+
+  Optional& operator=(const Optional& other) {
+    if (other.storage_.is_null_) {
+      FreeIfNeeded();
+      return *this;
+    }
+
+    InitOrAssign(other.value());
+    return *this;
+  }
+
+  Optional& operator=(Optional&& other) {
+    if (other.storage_.is_null_) {
+      FreeIfNeeded();
+      return *this;
+    }
+
+    InitOrAssign(std::move(other.value()));
+    return *this;
+  }
+
+  template <class U>
+  typename std::enable_if<std::is_same<std::decay<U>, T>::value,
+                          Optional&>::type
+  operator=(U&& value) {
+    InitOrAssign(std::forward<U>(value));
+    return *this;
+  }
+
+  // TODO(mlamouri): can't use 'constexpr' with DCHECK.
+  const T* operator->() const {
+    DCHECK(!storage_.is_null_);
+    return &value();
+  }
+
+  // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
+  // meant to be 'constexpr const'.
+  T* operator->() {
+    DCHECK(!storage_.is_null_);
+    return &value();
+  }
+
+  constexpr const T& operator*() const& { return value(); }
+
+  // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
+  // meant to be 'constexpr const'.
+  T& operator*() & { return value(); }
+
+  constexpr const T&& operator*() const&& { return std::move(value()); }
+
+  // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
+  // meant to be 'constexpr const'.
+  T&& operator*() && { return std::move(value()); }
+
+  constexpr explicit operator bool() const { return !storage_.is_null_; }
+
+  // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
+  // meant to be 'constexpr const'.
+  T& value() & {
+    DCHECK(!storage_.is_null_);
+    return *storage_.buffer_.template data_as<T>();
+  }
+
+  // TODO(mlamouri): can't use 'constexpr' with DCHECK.
+  const T& value() const& {
+    DCHECK(!storage_.is_null_);
+    return *storage_.buffer_.template data_as<T>();
+  }
+
+  // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
+  // meant to be 'constexpr const'.
+  T&& value() && {
+    DCHECK(!storage_.is_null_);
+    return std::move(*storage_.buffer_.template data_as<T>());
+  }
+
+  // TODO(mlamouri): can't use 'constexpr' with DCHECK.
+  const T&& value() const&& {
+    DCHECK(!storage_.is_null_);
+    return std::move(*storage_.buffer_.template data_as<T>());
+  }
+
+  template <class U>
+  constexpr T value_or(U&& default_value) const& {
+    // TODO(mlamouri): add the following assert when possible:
+    // static_assert(std::is_copy_constructible<T>::value,
+    //               "T must be copy constructible");
+    static_assert(std::is_convertible<U, T>::value,
+                  "U must be convertible to T");
+    return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
+                             : value();
+  }
+
+  template <class U>
+  T value_or(U&& default_value) && {
+    // TODO(mlamouri): add the following assert when possible:
+    // static_assert(std::is_move_constructible<T>::value,
+    //               "T must be move constructible");
+    static_assert(std::is_convertible<U, T>::value,
+                  "U must be convertible to T");
+    return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value))
+                             : std::move(value());
+  }
+
+  void swap(Optional& other) {
+    if (storage_.is_null_ && other.storage_.is_null_)
+      return;
+
+    if (storage_.is_null_ != other.storage_.is_null_) {
+      if (storage_.is_null_) {
+        Init(std::move(*other.storage_.buffer_.template data_as<T>()));
+        other.FreeIfNeeded();
+      } else {
+        other.Init(std::move(*storage_.buffer_.template data_as<T>()));
+        FreeIfNeeded();
+      }
+      return;
+    }
+
+    DCHECK(!storage_.is_null_ && !other.storage_.is_null_);
+    using std::swap;
+    swap(**this, *other);
+  }
+
+  template <class... Args>
+  void emplace(Args&&... args) {
+    FreeIfNeeded();
+    Init(std::forward<Args>(args)...);
+  }
+
+ private:
+  void Init(const T& value) {
+    DCHECK(storage_.is_null_);
+    new (storage_.buffer_.void_data()) T(value);
+    storage_.is_null_ = false;
+  }
+
+  void Init(T&& value) {
+    DCHECK(storage_.is_null_);
+    new (storage_.buffer_.void_data()) T(std::move(value));
+    storage_.is_null_ = false;
+  }
+
+  template <class... Args>
+  void Init(Args&&... args) {
+    DCHECK(storage_.is_null_);
+    new (storage_.buffer_.void_data()) T(std::forward<Args>(args)...);
+    storage_.is_null_ = false;
+  }
+
+  void InitOrAssign(const T& value) {
+    if (storage_.is_null_)
+      Init(value);
+    else
+      *storage_.buffer_.template data_as<T>() = value;
+  }
+
+  void InitOrAssign(T&& value) {
+    if (storage_.is_null_)
+      Init(std::move(value));
+    else
+      *storage_.buffer_.template data_as<T>() = std::move(value);
+  }
+
+  void FreeIfNeeded() {
+    if (storage_.is_null_)
+      return;
+    storage_.buffer_.template data_as<T>()->~T();
+    storage_.is_null_ = true;
+  }
+
+  internal::OptionalStorage<T> storage_;
+};
+
+template <class T>
+constexpr bool operator==(const Optional<T>& lhs, const Optional<T>& rhs) {
+  return !!lhs != !!rhs ? false : lhs == nullopt || (*lhs == *rhs);
+}
+
+template <class T>
+constexpr bool operator!=(const Optional<T>& lhs, const Optional<T>& rhs) {
+  return !(lhs == rhs);
+}
+
+template <class T>
+constexpr bool operator<(const Optional<T>& lhs, const Optional<T>& rhs) {
+  return rhs == nullopt ? false : (lhs == nullopt ? true : *lhs < *rhs);
+}
+
+template <class T>
+constexpr bool operator<=(const Optional<T>& lhs, const Optional<T>& rhs) {
+  return !(rhs < lhs);
+}
+
+template <class T>
+constexpr bool operator>(const Optional<T>& lhs, const Optional<T>& rhs) {
+  return rhs < lhs;
+}
+
+template <class T>
+constexpr bool operator>=(const Optional<T>& lhs, const Optional<T>& rhs) {
+  return !(lhs < rhs);
+}
+
+template <class T>
+constexpr bool operator==(const Optional<T>& opt, base::nullopt_t) {
+  return !opt;
+}
+
+template <class T>
+constexpr bool operator==(base::nullopt_t, const Optional<T>& opt) {
+  return !opt;
+}
+
+template <class T>
+constexpr bool operator!=(const Optional<T>& opt, base::nullopt_t) {
+  return !!opt;
+}
+
+template <class T>
+constexpr bool operator!=(base::nullopt_t, const Optional<T>& opt) {
+  return !!opt;
+}
+
+template <class T>
+constexpr bool operator<(const Optional<T>& opt, base::nullopt_t) {
+  return false;
+}
+
+template <class T>
+constexpr bool operator<(base::nullopt_t, const Optional<T>& opt) {
+  return !!opt;
+}
+
+template <class T>
+constexpr bool operator<=(const Optional<T>& opt, base::nullopt_t) {
+  return !opt;
+}
+
+template <class T>
+constexpr bool operator<=(base::nullopt_t, const Optional<T>& opt) {
+  return true;
+}
+
+template <class T>
+constexpr bool operator>(const Optional<T>& opt, base::nullopt_t) {
+  return !!opt;
+}
+
+template <class T>
+constexpr bool operator>(base::nullopt_t, const Optional<T>& opt) {
+  return false;
+}
+
+template <class T>
+constexpr bool operator>=(const Optional<T>& opt, base::nullopt_t) {
+  return true;
+}
+
+template <class T>
+constexpr bool operator>=(base::nullopt_t, const Optional<T>& opt) {
+  return !opt;
+}
+
+template <class T>
+constexpr bool operator==(const Optional<T>& opt, const T& value) {
+  return opt != nullopt ? *opt == value : false;
+}
+
+template <class T>
+constexpr bool operator==(const T& value, const Optional<T>& opt) {
+  return opt == value;
+}
+
+template <class T>
+constexpr bool operator!=(const Optional<T>& opt, const T& value) {
+  return !(opt == value);
+}
+
+template <class T>
+constexpr bool operator!=(const T& value, const Optional<T>& opt) {
+  return !(opt == value);
+}
+
+template <class T>
+constexpr bool operator<(const Optional<T>& opt, const T& value) {
+  return opt != nullopt ? *opt < value : true;
+}
+
+template <class T>
+constexpr bool operator<(const T& value, const Optional<T>& opt) {
+  return opt != nullopt ? value < *opt : false;
+}
+
+template <class T>
+constexpr bool operator<=(const Optional<T>& opt, const T& value) {
+  return !(opt > value);
+}
+
+template <class T>
+constexpr bool operator<=(const T& value, const Optional<T>& opt) {
+  return !(value > opt);
+}
+
+template <class T>
+constexpr bool operator>(const Optional<T>& opt, const T& value) {
+  return value < opt;
+}
+
+template <class T>
+constexpr bool operator>(const T& value, const Optional<T>& opt) {
+  return opt < value;
+}
+
+template <class T>
+constexpr bool operator>=(const Optional<T>& opt, const T& value) {
+  return !(opt < value);
+}
+
+template <class T>
+constexpr bool operator>=(const T& value, const Optional<T>& opt) {
+  return !(value < opt);
+}
+
+template <class T>
+constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
+  return Optional<typename std::decay<T>::type>(std::forward<T>(value));
+}
+
+template <class T>
+void swap(Optional<T>& lhs, Optional<T>& rhs) {
+  lhs.swap(rhs);
+}
+
+}  // namespace base
+
+namespace std {
+
+template <class T>
+struct hash<base::Optional<T>> {
+  size_t operator()(const base::Optional<T>& opt) const {
+    return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
+  }
+};
+
+}  // namespace std
+
+#endif  // BASE_OPTIONAL_H_
diff --git a/libchrome/base/optional_unittest.cc b/libchrome/base/optional_unittest.cc
new file mode 100644
index 0000000..d6bf263
--- /dev/null
+++ b/libchrome/base/optional_unittest.cc
@@ -0,0 +1,1301 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/optional.h"
+
+#include <set>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Object used to test complex object with Optional<T> in addition of the move
+// semantics.
+class TestObject {
+ public:
+  enum class State {
+    DEFAULT_CONSTRUCTED,
+    VALUE_CONSTRUCTED,
+    COPY_CONSTRUCTED,
+    MOVE_CONSTRUCTED,
+    MOVED_FROM,
+    COPY_ASSIGNED,
+    MOVE_ASSIGNED,
+    SWAPPED,
+  };
+
+  TestObject() : foo_(0), bar_(0.0), state_(State::DEFAULT_CONSTRUCTED) {}
+
+  TestObject(int foo, double bar)
+      : foo_(foo), bar_(bar), state_(State::VALUE_CONSTRUCTED) {}
+
+  TestObject(const TestObject& other)
+      : foo_(other.foo_), bar_(other.bar_), state_(State::COPY_CONSTRUCTED) {}
+
+  TestObject(TestObject&& other)
+      : foo_(std::move(other.foo_)),
+        bar_(std::move(other.bar_)),
+        state_(State::MOVE_CONSTRUCTED) {
+    other.state_ = State::MOVED_FROM;
+  }
+
+  TestObject& operator=(const TestObject& other) {
+    foo_ = other.foo_;
+    bar_ = other.bar_;
+    state_ = State::COPY_ASSIGNED;
+    return *this;
+  }
+
+  TestObject& operator=(TestObject&& other) {
+    foo_ = other.foo_;
+    bar_ = other.bar_;
+    state_ = State::MOVE_ASSIGNED;
+    other.state_ = State::MOVED_FROM;
+    return *this;
+  }
+
+  void Swap(TestObject* other) {
+    using std::swap;
+    swap(foo_, other->foo_);
+    swap(bar_, other->bar_);
+    state_ = State::SWAPPED;
+    other->state_ = State::SWAPPED;
+  }
+
+  bool operator==(const TestObject& other) const {
+    return foo_ == other.foo_ && bar_ == other.bar_;
+  }
+
+  int foo() const { return foo_; }
+  State state() const { return state_; }
+
+ private:
+  int foo_;
+  double bar_;
+  State state_;
+};
+
+// Implementing Swappable concept.
+void swap(TestObject& lhs, TestObject& rhs) {
+  lhs.Swap(&rhs);
+}
+
+class NonTriviallyDestructible {
+  ~NonTriviallyDestructible() {}
+};
+
+}  // anonymous namespace
+
+static_assert(is_trivially_destructible<Optional<int>>::value,
+              "OptionalIsTriviallyDestructible");
+
+static_assert(
+    !is_trivially_destructible<Optional<NonTriviallyDestructible>>::value,
+    "OptionalIsTriviallyDestructible");
+
+TEST(OptionalTest, DefaultConstructor) {
+  {
+    Optional<float> o;
+    EXPECT_FALSE(o);
+  }
+
+  {
+    Optional<std::string> o;
+    EXPECT_FALSE(o);
+  }
+
+  {
+    Optional<TestObject> o;
+    EXPECT_FALSE(o);
+  }
+}
+
+TEST(OptionalTest, CopyConstructor) {
+  {
+    Optional<float> first(0.1f);
+    Optional<float> other(first);
+
+    EXPECT_TRUE(other);
+    EXPECT_EQ(other.value(), 0.1f);
+    EXPECT_EQ(first, other);
+  }
+
+  {
+    Optional<std::string> first("foo");
+    Optional<std::string> other(first);
+
+    EXPECT_TRUE(other);
+    EXPECT_EQ(other.value(), "foo");
+    EXPECT_EQ(first, other);
+  }
+
+  {
+    Optional<TestObject> first(TestObject(3, 0.1));
+    Optional<TestObject> other(first);
+
+    EXPECT_TRUE(!!other);
+    EXPECT_TRUE(other.value() == TestObject(3, 0.1));
+    EXPECT_TRUE(first == other);
+  }
+}
+
+TEST(OptionalTest, ValueConstructor) {
+  {
+    Optional<float> o(0.1f);
+    EXPECT_TRUE(o);
+    EXPECT_EQ(o.value(), 0.1f);
+  }
+
+  {
+    Optional<std::string> o("foo");
+    EXPECT_TRUE(o);
+    EXPECT_EQ(o.value(), "foo");
+  }
+
+  {
+    Optional<TestObject> o(TestObject(3, 0.1));
+    EXPECT_TRUE(!!o);
+    EXPECT_TRUE(o.value() == TestObject(3, 0.1));
+  }
+}
+
+TEST(OptionalTest, MoveConstructor) {
+  {
+    Optional<float> first(0.1f);
+    Optional<float> second(std::move(first));
+
+    EXPECT_TRUE(second);
+    EXPECT_EQ(second.value(), 0.1f);
+
+    EXPECT_TRUE(first);
+  }
+
+  {
+    Optional<std::string> first("foo");
+    Optional<std::string> second(std::move(first));
+
+    EXPECT_TRUE(second);
+    EXPECT_EQ("foo", second.value());
+
+    EXPECT_TRUE(first);
+  }
+
+  {
+    Optional<TestObject> first(TestObject(3, 0.1));
+    Optional<TestObject> second(std::move(first));
+
+    EXPECT_TRUE(!!second);
+    EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED, second->state());
+    EXPECT_TRUE(TestObject(3, 0.1) == second.value());
+
+    EXPECT_TRUE(!!first);
+    EXPECT_EQ(TestObject::State::MOVED_FROM, first->state());
+  }
+}
+
+TEST(OptionalTest, MoveValueConstructor) {
+  {
+    Optional<float> first(0.1f);
+    Optional<float> second(std::move(first.value()));
+
+    EXPECT_TRUE(second);
+    EXPECT_EQ(second.value(), 0.1f);
+
+    EXPECT_TRUE(first);
+  }
+
+  {
+    Optional<std::string> first("foo");
+    Optional<std::string> second(std::move(first.value()));
+
+    EXPECT_TRUE(second);
+    EXPECT_EQ("foo", second.value());
+
+    EXPECT_TRUE(first);
+  }
+
+  {
+    Optional<TestObject> first(TestObject(3, 0.1));
+    Optional<TestObject> second(std::move(first.value()));
+
+    EXPECT_TRUE(!!second);
+    EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED, second->state());
+    EXPECT_TRUE(TestObject(3, 0.1) == second.value());
+
+    EXPECT_TRUE(!!first);
+    EXPECT_EQ(TestObject::State::MOVED_FROM, first->state());
+  }
+}
+
+TEST(OptionalTest, ConstructorForwardArguments) {
+  {
+    Optional<float> a(base::in_place, 0.1f);
+    EXPECT_TRUE(a);
+    EXPECT_EQ(0.1f, a.value());
+  }
+
+  {
+    Optional<std::string> a(base::in_place, "foo");
+    EXPECT_TRUE(a);
+    EXPECT_EQ("foo", a.value());
+  }
+
+  {
+    Optional<TestObject> a(base::in_place, 0, 0.1);
+    EXPECT_TRUE(!!a);
+    EXPECT_TRUE(TestObject(0, 0.1) == a.value());
+  }
+}
+
+TEST(OptionalTest, NulloptConstructor) {
+  Optional<int> a = base::nullopt;
+  EXPECT_FALSE(a);
+}
+
+TEST(OptionalTest, AssignValue) {
+  {
+    Optional<float> a;
+    EXPECT_FALSE(a);
+    a = 0.1f;
+    EXPECT_TRUE(a);
+
+    Optional<float> b(0.1f);
+    EXPECT_TRUE(a == b);
+  }
+
+  {
+    Optional<std::string> a;
+    EXPECT_FALSE(a);
+    a = std::string("foo");
+    EXPECT_TRUE(a);
+
+    Optional<std::string> b(std::string("foo"));
+    EXPECT_EQ(a, b);
+  }
+
+  {
+    Optional<TestObject> a;
+    EXPECT_FALSE(!!a);
+    a = TestObject(3, 0.1);
+    EXPECT_TRUE(!!a);
+
+    Optional<TestObject> b(TestObject(3, 0.1));
+    EXPECT_TRUE(a == b);
+  }
+
+  {
+    Optional<TestObject> a = TestObject(4, 1.0);
+    EXPECT_TRUE(!!a);
+    a = TestObject(3, 0.1);
+    EXPECT_TRUE(!!a);
+
+    Optional<TestObject> b(TestObject(3, 0.1));
+    EXPECT_TRUE(a == b);
+  }
+}
+
+TEST(OptionalTest, AssignObject) {
+  {
+    Optional<float> a;
+    Optional<float> b(0.1f);
+    a = b;
+
+    EXPECT_TRUE(a);
+    EXPECT_EQ(a.value(), 0.1f);
+    EXPECT_EQ(a, b);
+  }
+
+  {
+    Optional<std::string> a;
+    Optional<std::string> b("foo");
+    a = b;
+
+    EXPECT_TRUE(a);
+    EXPECT_EQ(a.value(), "foo");
+    EXPECT_EQ(a, b);
+  }
+
+  {
+    Optional<TestObject> a;
+    Optional<TestObject> b(TestObject(3, 0.1));
+    a = b;
+
+    EXPECT_TRUE(!!a);
+    EXPECT_TRUE(a.value() == TestObject(3, 0.1));
+    EXPECT_TRUE(a == b);
+  }
+
+  {
+    Optional<TestObject> a(TestObject(4, 1.0));
+    Optional<TestObject> b(TestObject(3, 0.1));
+    a = b;
+
+    EXPECT_TRUE(!!a);
+    EXPECT_TRUE(a.value() == TestObject(3, 0.1));
+    EXPECT_TRUE(a == b);
+  }
+}
+
+TEST(OptionalTest, AssignObject_rvalue) {
+  {
+    Optional<float> a;
+    Optional<float> b(0.1f);
+    a = std::move(b);
+
+    EXPECT_TRUE(a);
+    EXPECT_TRUE(b);
+    EXPECT_EQ(0.1f, a.value());
+  }
+
+  {
+    Optional<std::string> a;
+    Optional<std::string> b("foo");
+    a = std::move(b);
+
+    EXPECT_TRUE(a);
+    EXPECT_TRUE(b);
+    EXPECT_EQ("foo", a.value());
+  }
+
+  {
+    Optional<TestObject> a;
+    Optional<TestObject> b(TestObject(3, 0.1));
+    a = std::move(b);
+
+    EXPECT_TRUE(!!a);
+    EXPECT_TRUE(!!b);
+    EXPECT_TRUE(TestObject(3, 0.1) == a.value());
+
+    EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED, a->state());
+    EXPECT_EQ(TestObject::State::MOVED_FROM, b->state());
+  }
+
+  {
+    Optional<TestObject> a(TestObject(4, 1.0));
+    Optional<TestObject> b(TestObject(3, 0.1));
+    a = std::move(b);
+
+    EXPECT_TRUE(!!a);
+    EXPECT_TRUE(!!b);
+    EXPECT_TRUE(TestObject(3, 0.1) == a.value());
+
+    EXPECT_EQ(TestObject::State::MOVE_ASSIGNED, a->state());
+    EXPECT_EQ(TestObject::State::MOVED_FROM, b->state());
+  }
+}
+
+TEST(OptionalTest, AssignNull) {
+  {
+    Optional<float> a(0.1f);
+    Optional<float> b(0.2f);
+    a = base::nullopt;
+    b = base::nullopt;
+    EXPECT_EQ(a, b);
+  }
+
+  {
+    Optional<std::string> a("foo");
+    Optional<std::string> b("bar");
+    a = base::nullopt;
+    b = base::nullopt;
+    EXPECT_EQ(a, b);
+  }
+
+  {
+    Optional<TestObject> a(TestObject(3, 0.1));
+    Optional<TestObject> b(TestObject(4, 1.0));
+    a = base::nullopt;
+    b = base::nullopt;
+    EXPECT_TRUE(a == b);
+  }
+}
+
+TEST(OptionalTest, OperatorStar) {
+  {
+    Optional<float> a(0.1f);
+    EXPECT_EQ(a.value(), *a);
+  }
+
+  {
+    Optional<std::string> a("foo");
+    EXPECT_EQ(a.value(), *a);
+  }
+
+  {
+    Optional<TestObject> a(TestObject(3, 0.1));
+    EXPECT_EQ(a.value(), *a);
+  }
+}
+
+TEST(OptionalTest, OperatorStar_rvalue) {
+  EXPECT_EQ(0.1f, *Optional<float>(0.1f));
+  EXPECT_EQ(std::string("foo"), *Optional<std::string>("foo"));
+  EXPECT_TRUE(TestObject(3, 0.1) == *Optional<TestObject>(TestObject(3, 0.1)));
+}
+
+TEST(OptionalTest, OperatorArrow) {
+  Optional<TestObject> a(TestObject(3, 0.1));
+  EXPECT_EQ(a->foo(), 3);
+}
+
+TEST(OptionalTest, Value_rvalue) {
+  EXPECT_EQ(0.1f, Optional<float>(0.1f).value());
+  EXPECT_EQ(std::string("foo"), Optional<std::string>("foo").value());
+  EXPECT_TRUE(TestObject(3, 0.1) ==
+              Optional<TestObject>(TestObject(3, 0.1)).value());
+}
+
+TEST(OptionalTest, ValueOr) {
+  {
+    Optional<float> a;
+    EXPECT_EQ(0.0f, a.value_or(0.0f));
+
+    a = 0.1f;
+    EXPECT_EQ(0.1f, a.value_or(0.0f));
+
+    a = base::nullopt;
+    EXPECT_EQ(0.0f, a.value_or(0.0f));
+  }
+
+  {
+    Optional<std::string> a;
+    EXPECT_EQ("bar", a.value_or("bar"));
+
+    a = std::string("foo");
+    EXPECT_EQ(std::string("foo"), a.value_or("bar"));
+
+    a = base::nullopt;
+    EXPECT_EQ(std::string("bar"), a.value_or("bar"));
+  }
+
+  {
+    Optional<TestObject> a;
+    EXPECT_TRUE(a.value_or(TestObject(1, 0.3)) == TestObject(1, 0.3));
+
+    a = TestObject(3, 0.1);
+    EXPECT_TRUE(a.value_or(TestObject(1, 0.3)) == TestObject(3, 0.1));
+
+    a = base::nullopt;
+    EXPECT_TRUE(a.value_or(TestObject(1, 0.3)) == TestObject(1, 0.3));
+  }
+}
+
+TEST(OptionalTest, Swap_bothNoValue) {
+  Optional<TestObject> a, b;
+  a.swap(b);
+
+  EXPECT_FALSE(a);
+  EXPECT_FALSE(b);
+  EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42)));
+}
+
+TEST(OptionalTest, Swap_inHasValue) {
+  Optional<TestObject> a(TestObject(1, 0.3));
+  Optional<TestObject> b;
+  a.swap(b);
+
+  EXPECT_FALSE(a);
+
+  EXPECT_TRUE(!!b);
+  EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(1, 0.3) == b.value_or(TestObject(42, 0.42)));
+}
+
+TEST(OptionalTest, Swap_outHasValue) {
+  Optional<TestObject> a;
+  Optional<TestObject> b(TestObject(1, 0.3));
+  a.swap(b);
+
+  EXPECT_TRUE(!!a);
+  EXPECT_FALSE(!!b);
+  EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42)));
+}
+
+TEST(OptionalTest, Swap_bothValue) {
+  Optional<TestObject> a(TestObject(0, 0.1));
+  Optional<TestObject> b(TestObject(1, 0.3));
+  a.swap(b);
+
+  EXPECT_TRUE(!!a);
+  EXPECT_TRUE(!!b);
+  EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(0, 0.1) == b.value_or(TestObject(42, 0.42)));
+  EXPECT_EQ(TestObject::State::SWAPPED, a->state());
+  EXPECT_EQ(TestObject::State::SWAPPED, b->state());
+}
+
+TEST(OptionalTest, Emplace) {
+  {
+    Optional<float> a(0.1f);
+    a.emplace(0.3f);
+
+    EXPECT_TRUE(a);
+    EXPECT_EQ(0.3f, a.value());
+  }
+
+  {
+    Optional<std::string> a("foo");
+    a.emplace("bar");
+
+    EXPECT_TRUE(a);
+    EXPECT_EQ("bar", a.value());
+  }
+
+  {
+    Optional<TestObject> a(TestObject(0, 0.1));
+    a.emplace(TestObject(1, 0.2));
+
+    EXPECT_TRUE(!!a);
+    EXPECT_TRUE(TestObject(1, 0.2) == a.value());
+  }
+}
+
+TEST(OptionalTest, Equals_TwoEmpty) {
+  Optional<int> a;
+  Optional<int> b;
+
+  EXPECT_TRUE(a == b);
+}
+
+TEST(OptionalTest, Equals_TwoEquals) {
+  Optional<int> a(1);
+  Optional<int> b(1);
+
+  EXPECT_TRUE(a == b);
+}
+
+TEST(OptionalTest, Equals_OneEmpty) {
+  Optional<int> a;
+  Optional<int> b(1);
+
+  EXPECT_FALSE(a == b);
+}
+
+TEST(OptionalTest, Equals_TwoDifferent) {
+  Optional<int> a(0);
+  Optional<int> b(1);
+
+  EXPECT_FALSE(a == b);
+}
+
+TEST(OptionalTest, NotEquals_TwoEmpty) {
+  Optional<int> a;
+  Optional<int> b;
+
+  EXPECT_FALSE(a != b);
+}
+
+TEST(OptionalTest, NotEquals_TwoEquals) {
+  Optional<int> a(1);
+  Optional<int> b(1);
+
+  EXPECT_FALSE(a != b);
+}
+
+TEST(OptionalTest, NotEquals_OneEmpty) {
+  Optional<int> a;
+  Optional<int> b(1);
+
+  EXPECT_TRUE(a != b);
+}
+
+TEST(OptionalTest, NotEquals_TwoDifferent) {
+  Optional<int> a(0);
+  Optional<int> b(1);
+
+  EXPECT_TRUE(a != b);
+}
+
+TEST(OptionalTest, Less_LeftEmpty) {
+  Optional<int> l;
+  Optional<int> r(1);
+
+  EXPECT_TRUE(l < r);
+}
+
+TEST(OptionalTest, Less_RightEmpty) {
+  Optional<int> l(1);
+  Optional<int> r;
+
+  EXPECT_FALSE(l < r);
+}
+
+TEST(OptionalTest, Less_BothEmpty) {
+  Optional<int> l;
+  Optional<int> r;
+
+  EXPECT_FALSE(l < r);
+}
+
+TEST(OptionalTest, Less_BothValues) {
+  {
+    Optional<int> l(1);
+    Optional<int> r(2);
+
+    EXPECT_TRUE(l < r);
+  }
+  {
+    Optional<int> l(2);
+    Optional<int> r(1);
+
+    EXPECT_FALSE(l < r);
+  }
+  {
+    Optional<int> l(1);
+    Optional<int> r(1);
+
+    EXPECT_FALSE(l < r);
+  }
+}
+
+TEST(OptionalTest, LessEq_LeftEmpty) {
+  Optional<int> l;
+  Optional<int> r(1);
+
+  EXPECT_TRUE(l <= r);
+}
+
+TEST(OptionalTest, LessEq_RightEmpty) {
+  Optional<int> l(1);
+  Optional<int> r;
+
+  EXPECT_FALSE(l <= r);
+}
+
+TEST(OptionalTest, LessEq_BothEmpty) {
+  Optional<int> l;
+  Optional<int> r;
+
+  EXPECT_TRUE(l <= r);
+}
+
+TEST(OptionalTest, LessEq_BothValues) {
+  {
+    Optional<int> l(1);
+    Optional<int> r(2);
+
+    EXPECT_TRUE(l <= r);
+  }
+  {
+    Optional<int> l(2);
+    Optional<int> r(1);
+
+    EXPECT_FALSE(l <= r);
+  }
+  {
+    Optional<int> l(1);
+    Optional<int> r(1);
+
+    EXPECT_TRUE(l <= r);
+  }
+}
+
+TEST(OptionalTest, Greater_BothEmpty) {
+  Optional<int> l;
+  Optional<int> r;
+
+  EXPECT_FALSE(l > r);
+}
+
+TEST(OptionalTest, Greater_LeftEmpty) {
+  Optional<int> l;
+  Optional<int> r(1);
+
+  EXPECT_FALSE(l > r);
+}
+
+TEST(OptionalTest, Greater_RightEmpty) {
+  Optional<int> l(1);
+  Optional<int> r;
+
+  EXPECT_TRUE(l > r);
+}
+
+TEST(OptionalTest, Greater_BothValue) {
+  {
+    Optional<int> l(1);
+    Optional<int> r(2);
+
+    EXPECT_FALSE(l > r);
+  }
+  {
+    Optional<int> l(2);
+    Optional<int> r(1);
+
+    EXPECT_TRUE(l > r);
+  }
+  {
+    Optional<int> l(1);
+    Optional<int> r(1);
+
+    EXPECT_FALSE(l > r);
+  }
+}
+
+TEST(OptionalTest, GreaterEq_BothEmpty) {
+  Optional<int> l;
+  Optional<int> r;
+
+  EXPECT_TRUE(l >= r);
+}
+
+TEST(OptionalTest, GreaterEq_LeftEmpty) {
+  Optional<int> l;
+  Optional<int> r(1);
+
+  EXPECT_FALSE(l >= r);
+}
+
+TEST(OptionalTest, GreaterEq_RightEmpty) {
+  Optional<int> l(1);
+  Optional<int> r;
+
+  EXPECT_TRUE(l >= r);
+}
+
+TEST(OptionalTest, GreaterEq_BothValue) {
+  {
+    Optional<int> l(1);
+    Optional<int> r(2);
+
+    EXPECT_FALSE(l >= r);
+  }
+  {
+    Optional<int> l(2);
+    Optional<int> r(1);
+
+    EXPECT_TRUE(l >= r);
+  }
+  {
+    Optional<int> l(1);
+    Optional<int> r(1);
+
+    EXPECT_TRUE(l >= r);
+  }
+}
+
+TEST(OptionalTest, OptNullEq) {
+  {
+    Optional<int> opt;
+    EXPECT_TRUE(opt == base::nullopt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(opt == base::nullopt);
+  }
+}
+
+TEST(OptionalTest, NullOptEq) {
+  {
+    Optional<int> opt;
+    EXPECT_TRUE(base::nullopt == opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(base::nullopt == opt);
+  }
+}
+
+TEST(OptionalTest, OptNullNotEq) {
+  {
+    Optional<int> opt;
+    EXPECT_FALSE(opt != base::nullopt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(opt != base::nullopt);
+  }
+}
+
+TEST(OptionalTest, NullOptNotEq) {
+  {
+    Optional<int> opt;
+    EXPECT_FALSE(base::nullopt != opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(base::nullopt != opt);
+  }
+}
+
+TEST(OptionalTest, OptNullLower) {
+  {
+    Optional<int> opt;
+    EXPECT_FALSE(opt < base::nullopt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(opt < base::nullopt);
+  }
+}
+
+TEST(OptionalTest, NullOptLower) {
+  {
+    Optional<int> opt;
+    EXPECT_FALSE(base::nullopt < opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(base::nullopt < opt);
+  }
+}
+
+TEST(OptionalTest, OptNullLowerEq) {
+  {
+    Optional<int> opt;
+    EXPECT_TRUE(opt <= base::nullopt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(opt <= base::nullopt);
+  }
+}
+
+TEST(OptionalTest, NullOptLowerEq) {
+  {
+    Optional<int> opt;
+    EXPECT_TRUE(base::nullopt <= opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(base::nullopt <= opt);
+  }
+}
+
+TEST(OptionalTest, OptNullGreater) {
+  {
+    Optional<int> opt;
+    EXPECT_FALSE(opt > base::nullopt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(opt > base::nullopt);
+  }
+}
+
+TEST(OptionalTest, NullOptGreater) {
+  {
+    Optional<int> opt;
+    EXPECT_FALSE(base::nullopt > opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(base::nullopt > opt);
+  }
+}
+
+TEST(OptionalTest, OptNullGreaterEq) {
+  {
+    Optional<int> opt;
+    EXPECT_TRUE(opt >= base::nullopt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(opt >= base::nullopt);
+  }
+}
+
+TEST(OptionalTest, NullOptGreaterEq) {
+  {
+    Optional<int> opt;
+    EXPECT_TRUE(base::nullopt >= opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(base::nullopt >= opt);
+  }
+}
+
+TEST(OptionalTest, ValueEq_Empty) {
+  Optional<int> opt;
+  EXPECT_FALSE(opt == 1);
+}
+
+TEST(OptionalTest, ValueEq_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_FALSE(opt == 1);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(opt == 1);
+  }
+}
+
+TEST(OptionalTest, EqValue_Empty) {
+  Optional<int> opt;
+  EXPECT_FALSE(1 == opt);
+}
+
+TEST(OptionalTest, EqValue_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_FALSE(1 == opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(1 == opt);
+  }
+}
+
+TEST(OptionalTest, ValueNotEq_Empty) {
+  Optional<int> opt;
+  EXPECT_TRUE(opt != 1);
+}
+
+TEST(OptionalTest, ValueNotEq_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_TRUE(opt != 1);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(opt != 1);
+  }
+}
+
+TEST(OptionalTest, NotEqValue_Empty) {
+  Optional<int> opt;
+  EXPECT_TRUE(1 != opt);
+}
+
+TEST(OptionalTest, NotEqValue_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_TRUE(1 != opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(1 != opt);
+  }
+}
+
+TEST(OptionalTest, ValueLess_Empty) {
+  Optional<int> opt;
+  EXPECT_TRUE(opt < 1);
+}
+
+TEST(OptionalTest, ValueLess_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_TRUE(opt < 1);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(opt < 1);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_FALSE(opt < 1);
+  }
+}
+
+TEST(OptionalTest, LessValue_Empty) {
+  Optional<int> opt;
+  EXPECT_FALSE(1 < opt);
+}
+
+TEST(OptionalTest, LessValue_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_FALSE(1 < opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(1 < opt);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_TRUE(1 < opt);
+  }
+}
+
+TEST(OptionalTest, ValueLessEq_Empty) {
+  Optional<int> opt;
+  EXPECT_TRUE(opt <= 1);
+}
+
+TEST(OptionalTest, ValueLessEq_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_TRUE(opt <= 1);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(opt <= 1);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_FALSE(opt <= 1);
+  }
+}
+
+TEST(OptionalTest, LessEqValue_Empty) {
+  Optional<int> opt;
+  EXPECT_FALSE(1 <= opt);
+}
+
+TEST(OptionalTest, LessEqValue_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_FALSE(1 <= opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(1 <= opt);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_TRUE(1 <= opt);
+  }
+}
+
+TEST(OptionalTest, ValueGreater_Empty) {
+  Optional<int> opt;
+  EXPECT_FALSE(opt > 1);
+}
+
+TEST(OptionalTest, ValueGreater_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_FALSE(opt > 1);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(opt > 1);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_TRUE(opt > 1);
+  }
+}
+
+TEST(OptionalTest, GreaterValue_Empty) {
+  Optional<int> opt;
+  EXPECT_TRUE(1 > opt);
+}
+
+TEST(OptionalTest, GreaterValue_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_TRUE(1 > opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_FALSE(1 > opt);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_FALSE(1 > opt);
+  }
+}
+
+TEST(OptionalTest, ValueGreaterEq_Empty) {
+  Optional<int> opt;
+  EXPECT_FALSE(opt >= 1);
+}
+
+TEST(OptionalTest, ValueGreaterEq_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_FALSE(opt >= 1);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(opt >= 1);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_TRUE(opt >= 1);
+  }
+}
+
+TEST(OptionalTest, GreaterEqValue_Empty) {
+  Optional<int> opt;
+  EXPECT_TRUE(1 >= opt);
+}
+
+TEST(OptionalTest, GreaterEqValue_NotEmpty) {
+  {
+    Optional<int> opt(0);
+    EXPECT_TRUE(1 >= opt);
+  }
+  {
+    Optional<int> opt(1);
+    EXPECT_TRUE(1 >= opt);
+  }
+  {
+    Optional<int> opt(2);
+    EXPECT_FALSE(1 >= opt);
+  }
+}
+
+TEST(OptionalTest, NotEquals) {
+  {
+    Optional<float> a(0.1f);
+    Optional<float> b(0.2f);
+    EXPECT_NE(a, b);
+  }
+
+  {
+    Optional<std::string> a("foo");
+    Optional<std::string> b("bar");
+    EXPECT_NE(a, b);
+  }
+
+  {
+    Optional<TestObject> a(TestObject(3, 0.1));
+    Optional<TestObject> b(TestObject(4, 1.0));
+    EXPECT_TRUE(a != b);
+  }
+}
+
+TEST(OptionalTest, NotEqualsNull) {
+  {
+    Optional<float> a(0.1f);
+    Optional<float> b(0.1f);
+    b = base::nullopt;
+    EXPECT_NE(a, b);
+  }
+
+  {
+    Optional<std::string> a("foo");
+    Optional<std::string> b("foo");
+    b = base::nullopt;
+    EXPECT_NE(a, b);
+  }
+
+  {
+    Optional<TestObject> a(TestObject(3, 0.1));
+    Optional<TestObject> b(TestObject(3, 0.1));
+    b = base::nullopt;
+    EXPECT_TRUE(a != b);
+  }
+}
+
+TEST(OptionalTest, MakeOptional) {
+  {
+    Optional<float> o = base::make_optional(32.f);
+    EXPECT_TRUE(o);
+    EXPECT_EQ(32.f, *o);
+
+    float value = 3.f;
+    o = base::make_optional(std::move(value));
+    EXPECT_TRUE(o);
+    EXPECT_EQ(3.f, *o);
+  }
+
+  {
+    Optional<std::string> o = base::make_optional(std::string("foo"));
+    EXPECT_TRUE(o);
+    EXPECT_EQ("foo", *o);
+
+    std::string value = "bar";
+    o = base::make_optional(std::move(value));
+    EXPECT_TRUE(o);
+    EXPECT_EQ(std::string("bar"), *o);
+  }
+
+  {
+    Optional<TestObject> o = base::make_optional(TestObject(3, 0.1));
+    EXPECT_TRUE(!!o);
+    EXPECT_TRUE(TestObject(3, 0.1) == *o);
+
+    TestObject value = TestObject(0, 0.42);
+    o = base::make_optional(std::move(value));
+    EXPECT_TRUE(!!o);
+    EXPECT_TRUE(TestObject(0, 0.42) == *o);
+    EXPECT_EQ(TestObject::State::MOVED_FROM, value.state());
+    EXPECT_EQ(TestObject::State::MOVE_ASSIGNED, o->state());
+
+    EXPECT_EQ(TestObject::State::MOVE_CONSTRUCTED,
+              base::make_optional(std::move(value))->state());
+  }
+}
+
+TEST(OptionalTest, NonMemberSwap_bothNoValue) {
+  Optional<TestObject> a, b;
+  base::swap(a, b);
+
+  EXPECT_FALSE(!!a);
+  EXPECT_FALSE(!!b);
+  EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42)));
+}
+
+TEST(OptionalTest, NonMemberSwap_inHasValue) {
+  Optional<TestObject> a(TestObject(1, 0.3));
+  Optional<TestObject> b;
+  base::swap(a, b);
+
+  EXPECT_FALSE(!!a);
+  EXPECT_TRUE(!!b);
+  EXPECT_TRUE(TestObject(42, 0.42) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(1, 0.3) == b.value_or(TestObject(42, 0.42)));
+}
+
+TEST(OptionalTest, NonMemberSwap_outHasValue) {
+  Optional<TestObject> a;
+  Optional<TestObject> b(TestObject(1, 0.3));
+  base::swap(a, b);
+
+  EXPECT_TRUE(!!a);
+  EXPECT_FALSE(!!b);
+  EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(42, 0.42) == b.value_or(TestObject(42, 0.42)));
+}
+
+TEST(OptionalTest, NonMemberSwap_bothValue) {
+  Optional<TestObject> a(TestObject(0, 0.1));
+  Optional<TestObject> b(TestObject(1, 0.3));
+  base::swap(a, b);
+
+  EXPECT_TRUE(!!a);
+  EXPECT_TRUE(!!b);
+  EXPECT_TRUE(TestObject(1, 0.3) == a.value_or(TestObject(42, 0.42)));
+  EXPECT_TRUE(TestObject(0, 0.1) == b.value_or(TestObject(42, 0.42)));
+  EXPECT_EQ(TestObject::State::SWAPPED, a->state());
+  EXPECT_EQ(TestObject::State::SWAPPED, b->state());
+}
+
+TEST(OptionalTest, Hash_OptionalReflectsInternal) {
+  {
+    std::hash<int> int_hash;
+    std::hash<Optional<int>> opt_int_hash;
+
+    EXPECT_EQ(int_hash(1), opt_int_hash(Optional<int>(1)));
+  }
+
+  {
+    std::hash<std::string> str_hash;
+    std::hash<Optional<std::string>> opt_str_hash;
+
+    EXPECT_EQ(str_hash(std::string("foobar")),
+              opt_str_hash(Optional<std::string>(std::string("foobar"))));
+  }
+}
+
+TEST(OptionalTest, Hash_NullOptEqualsNullOpt) {
+  std::hash<Optional<int>> opt_int_hash;
+  std::hash<Optional<std::string>> opt_str_hash;
+
+  EXPECT_EQ(opt_str_hash(Optional<std::string>()),
+            opt_int_hash(Optional<int>()));
+}
+
+TEST(OptionalTest, Hash_UseInSet) {
+  std::set<Optional<int>> setOptInt;
+
+  EXPECT_EQ(setOptInt.end(), setOptInt.find(42));
+
+  setOptInt.insert(Optional<int>(3));
+  EXPECT_EQ(setOptInt.end(), setOptInt.find(42));
+  EXPECT_NE(setOptInt.end(), setOptInt.find(3));
+}
+
+}  // namespace base
diff --git a/libchrome/base/os_compat_android.cc b/libchrome/base/os_compat_android.cc
new file mode 100644
index 0000000..1eb6536
--- /dev/null
+++ b/libchrome/base/os_compat_android.cc
@@ -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/os_compat_android.h"
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <limits.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/libchrome/base/os_compat_android.h b/libchrome/base/os_compat_android.h
new file mode 100644
index 0000000..0f25444
--- /dev/null
+++ b/libchrome/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/libchrome/base/os_compat_android_unittest.cc b/libchrome/base/os_compat_android_unittest.cc
new file mode 100644
index 0000000..7fbdc6d
--- /dev/null
+++ b/libchrome/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/libchrome/base/pending_task.cc b/libchrome/base/pending_task.cc
new file mode 100644
index 0000000..73834bd
--- /dev/null
+++ b/libchrome/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,
+                         base::Closure task)
+    : base::TrackingInfo(posted_from, TimeTicks()),
+      task(std::move(task)),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(true),
+      is_high_res(false) {
+}
+
+PendingTask::PendingTask(const tracked_objects::Location& posted_from,
+                         base::Closure task,
+                         TimeTicks delayed_run_time,
+                         bool nestable)
+    : base::TrackingInfo(posted_from, delayed_run_time),
+      task(std::move(task)),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(nestable),
+      is_high_res(false) {
+}
+
+PendingTask::PendingTask(PendingTask&& other) = default;
+
+PendingTask::~PendingTask() {
+}
+
+PendingTask& PendingTask::operator=(PendingTask&& other) = default;
+
+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;
+}
+
+}  // namespace base
diff --git a/libchrome/base/pending_task.h b/libchrome/base/pending_task.h
new file mode 100644
index 0000000..5761653
--- /dev/null
+++ b/libchrome/base/pending_task.h
@@ -0,0 +1,58 @@
+// 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,
+              Closure task);
+  PendingTask(const tracked_objects::Location& posted_from,
+              Closure task,
+              TimeTicks delayed_run_time,
+              bool nestable);
+  PendingTask(PendingTask&& other);
+  ~PendingTask();
+
+  PendingTask& operator=(PendingTask&& other);
+
+  // 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;
+};
+
+using TaskQueue = std::queue<PendingTask>;
+
+// PendingTasks are sorted by their |delayed_run_time| property.
+using DelayedTaskQueue = std::priority_queue<base::PendingTask>;
+
+}  // namespace base
+
+#endif  // BASE_PENDING_TASK_H_
diff --git a/libchrome/base/pickle.cc b/libchrome/base/pickle.cc
new file mode 100644
index 0000000..4ef167b
--- /dev/null
+++ b/libchrome/base/pickle.cc
@@ -0,0 +1,483 @@
+// Copyright (c) 2012 The Chromium Authors. All 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()
+#include <limits>
+
+#include "base/bits.h"
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "build/build_config.h"
+
+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_t))
+    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 = bits::Align(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_t overflow.
+  int64_t num_bytes = static_cast<int64_t>(num_elements) * size_element;
+  int num_bytes32 = static_cast<int>(num_bytes);
+  if (num_bytes != static_cast<int64_t>(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) {
+  // Always read long as a 64-bit value to ensure compatibility between 32-bit
+  // and 64-bit processes.
+  int64_t result_int64 = 0;
+  if (!ReadBuiltinType(&result_int64))
+    return false;
+  // CHECK if the cast truncates the value so that we know to change this IPC
+  // parameter to use int64_t.
+  *result = base::checked_cast<long>(result_int64);
+  return true;
+}
+
+bool PickleIterator::ReadUInt16(uint16_t* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt32(uint32_t* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadInt64(int64_t* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt64(uint64_t* result) {
+  return ReadBuiltinType(result);
+}
+
+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;
+}
+
+PickleSizer::PickleSizer() {}
+
+PickleSizer::~PickleSizer() {}
+
+void PickleSizer::AddString(const StringPiece& value) {
+  AddInt();
+  AddBytes(static_cast<int>(value.size()));
+}
+
+void PickleSizer::AddString16(const StringPiece16& value) {
+  AddInt();
+  AddBytes(static_cast<int>(value.size() * sizeof(char16)));
+}
+
+void PickleSizer::AddData(int length) {
+  CHECK_GE(length, 0);
+  AddInt();
+  AddBytes(length);
+}
+
+void PickleSizer::AddBytes(int length) {
+  payload_size_ += bits::Align(length, sizeof(uint32_t));
+}
+
+void PickleSizer::AddAttachment() {
+  // From IPC::Message::WriteAttachment
+  AddBool();
+  AddInt();
+}
+
+template <size_t length> void PickleSizer::AddBytesStatic() {
+  DCHECK_LE(length, static_cast<size_t>(std::numeric_limits<int>::max()));
+  AddBytes(length);
+}
+
+template void PickleSizer::AddBytesStatic<2>();
+template void PickleSizer::AddBytesStatic<4>();
+template void PickleSizer::AddBytesStatic<8>();
+
+Pickle::Attachment::Attachment() {}
+
+Pickle::Attachment::~Attachment() {}
+
+// Payload is uint32_t aligned.
+
+Pickle::Pickle()
+    : header_(NULL),
+      header_size_(sizeof(Header)),
+      capacity_after_header_(0),
+      write_offset_(0) {
+  static_assert((Pickle::kPayloadUnit & (Pickle::kPayloadUnit - 1)) == 0,
+                "Pickle::kPayloadUnit must be a power of two");
+  Resize(kPayloadUnit);
+  header_->payload_size = 0;
+}
+
+Pickle::Pickle(int header_size)
+    : header_(NULL),
+      header_size_(bits::Align(header_size, sizeof(uint32_t))),
+      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_ != bits::Align(header_size_, sizeof(uint32_t)))
+    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_) {
+  Resize(other.header_->payload_size);
+  memcpy(header_, other.header_, header_size_ + 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 = bits::Align(length, sizeof(uint32_t));
+  DCHECK_GE(data_len, length);
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
+#endif
+  DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_)
+    Resize(capacity_after_header_ * 2 + new_size);
+}
+
+bool Pickle::WriteAttachment(scoped_refptr<Attachment> /*attachment*/) {
+  return false;
+}
+
+bool Pickle::ReadAttachment(base::PickleIterator* /*iter*/,
+                            scoped_refptr<Attachment>* /*attachment*/) const {
+  return false;
+}
+
+bool Pickle::HasAttachments() const {
+  return false;
+}
+
+void Pickle::Resize(size_t new_capacity) {
+  CHECK_NE(capacity_after_header_, kCapacityReadOnly);
+  capacity_after_header_ = bits::Align(new_capacity, kPayloadUnit);
+  void* p = realloc(header_, GetTotalAllocatedSize());
+  CHECK(p);
+  header_ = reinterpret_cast<Header*>(p);
+}
+
+void* Pickle::ClaimBytes(size_t num_bytes) {
+  void* p = ClaimUninitializedBytesInternal(num_bytes);
+  CHECK(p);
+  memset(p, 0, num_bytes);
+  return 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) {
+  size_t pickle_size = 0;
+  if (!PeekNext(header_size, start, end, &pickle_size))
+    return NULL;
+
+  if (pickle_size > static_cast<size_t>(end - start))
+    return NULL;
+
+  return start + pickle_size;
+}
+
+// static
+bool Pickle::PeekNext(size_t header_size,
+                      const char* start,
+                      const char* end,
+                      size_t* pickle_size) {
+  DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32_t)));
+  DCHECK_GE(header_size, sizeof(Header));
+  DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
+
+  size_t length = static_cast<size_t>(end - start);
+  if (length < sizeof(Header))
+    return false;
+
+  const Header* hdr = reinterpret_cast<const Header*>(start);
+  if (length < header_size)
+    return false;
+
+  if (hdr->payload_size > std::numeric_limits<size_t>::max() - header_size) {
+    // If payload_size causes an overflow, we return maximum possible
+    // pickle size to indicate that.
+    *pickle_size = std::numeric_limits<size_t>::max();
+  } else {
+    *pickle_size = header_size + hdr->payload_size;
+  }
+  return true;
+}
+
+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::ClaimUninitializedBytesInternal(size_t length) {
+  DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
+      << "oops: pickle is readonly";
+  size_t data_len = bits::Align(length, sizeof(uint32_t));
+  DCHECK_GE(data_len, length);
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
+#endif
+  DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_) {
+    size_t new_capacity = capacity_after_header_ * 2;
+    const size_t kPickleHeapAlign = 4096;
+    if (new_capacity > kPickleHeapAlign)
+      new_capacity = bits::Align(new_capacity, kPickleHeapAlign) - kPayloadUnit;
+    Resize(std::max(new_capacity, new_size));
+  }
+
+  char* write = mutable_payload() + write_offset_;
+  memset(write + length, 0, data_len - length);  // Always initialize padding
+  header_->payload_size = static_cast<uint32_t>(new_size);
+  write_offset_ = new_size;
+  return write;
+}
+
+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);
+  void* write = ClaimUninitializedBytesInternal(length);
+  memcpy(write, data, length);
+}
+
+}  // namespace base
diff --git a/libchrome/base/pickle.h b/libchrome/base/pickle.h
new file mode 100644
index 0000000..40f5d26
--- /dev/null
+++ b/libchrome/base/pickle.h
@@ -0,0 +1,385 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+#if defined(OS_POSIX)
+#include "base/files/file.h"
+#endif
+
+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_t* result) WARN_UNUSED_RESULT;
+  bool ReadUInt32(uint32_t* result) WARN_UNUSED_RESULT;
+  bool ReadInt64(int64_t* result) WARN_UNUSED_RESULT;
+  bool ReadUInt64(uint64_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:
+  // 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 an interface analogous to base::Pickle's WriteFoo()
+// methods and can be used to accurately compute the size of a hypothetical
+// Pickle's payload without having to reference the Pickle implementation.
+class BASE_EXPORT PickleSizer {
+ public:
+  PickleSizer();
+  ~PickleSizer();
+
+  // Returns the computed size of the payload.
+  size_t payload_size() const { return payload_size_; }
+
+  void AddBool() { return AddInt(); }
+  void AddInt() { AddPOD<int>(); }
+  void AddLong() { AddPOD<uint64_t>(); }
+  void AddUInt16() { return AddPOD<uint16_t>(); }
+  void AddUInt32() { return AddPOD<uint32_t>(); }
+  void AddInt64() { return AddPOD<int64_t>(); }
+  void AddUInt64() { return AddPOD<uint64_t>(); }
+  void AddFloat() { return AddPOD<float>(); }
+  void AddDouble() { return AddPOD<double>(); }
+  void AddString(const StringPiece& value);
+  void AddString16(const StringPiece16& value);
+  void AddData(int length);
+  void AddBytes(int length);
+  void AddAttachment();
+
+ private:
+  // Just like AddBytes() but with a compile-time size for performance.
+  template<size_t length> void BASE_EXPORT AddBytesStatic();
+
+  template <typename T>
+  void AddPOD() { AddBytesStatic<sizeof(T)>(); }
+
+  size_t payload_size_ = 0;
+};
+
+// 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:
+  // Auxiliary data attached to a Pickle. Pickle must be subclassed along with
+  // this interface in order to provide a concrete implementation of support
+  // for attachments. The base Pickle implementation does not accept
+  // attachments.
+  class BASE_EXPORT Attachment : public RefCountedThreadSafe<Attachment> {
+   public:
+    Attachment();
+
+   protected:
+    friend class RefCountedThreadSafe<Attachment>;
+    virtual ~Attachment();
+
+    DISALLOW_COPY_AND_ASSIGN(Attachment);
+  };
+
+  // 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);
+  }
+  bool WriteLong(long value) {
+    // Always write long as a 64-bit value to ensure compatibility between
+    // 32-bit and 64-bit processes.
+    return WritePOD(static_cast<int64_t>(value));
+  }
+  bool WriteUInt16(uint16_t value) { return WritePOD(value); }
+  bool WriteUInt32(uint32_t value) { return WritePOD(value); }
+  bool WriteInt64(int64_t value) { return WritePOD(value); }
+  bool WriteUInt64(uint64_t value) { return WritePOD(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);
+
+  // WriteAttachment appends |attachment| to the pickle. It returns
+  // false iff the set is full or if the Pickle implementation does not support
+  // attachments.
+  virtual bool WriteAttachment(scoped_refptr<Attachment> attachment);
+
+  // ReadAttachment parses an attachment given the parsing state |iter| and
+  // writes it to |*attachment|. It returns true on success.
+  virtual bool ReadAttachment(base::PickleIterator* iter,
+                              scoped_refptr<Attachment>* attachment) const;
+
+  // Indicates whether the pickle has any attachments.
+  virtual bool HasAttachments() const;
+
+  // 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_t 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);
+
+  // Claims |num_bytes| bytes of payload. This is similar to Reserve() in that
+  // it may grow the capacity, but it also advances the write offset of the
+  // pickle by |num_bytes|. Claimed memory, including padding, is zeroed.
+  //
+  // Returns the address of the first byte claimed.
+  void* ClaimBytes(size_t num_bytes);
+
+  // 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);
+
+  // Parse pickle header and return total size of the pickle. Data range
+  // doesn't need to contain entire pickle.
+  // Returns true if pickle header was found and parsed. Callers must check
+  // returned |pickle_size| for sanity (against maximum message size, etc).
+  // NOTE: when function successfully parses a header, but encounters an
+  // overflow during pickle size calculation, it sets |pickle_size| to the
+  // maximum size_t value and returns true.
+  static bool PeekNext(size_t header_size,
+                       const char* range_start,
+                       const char* range_end,
+                       size_t* pickle_size);
+
+  // 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* ClaimUninitializedBytesInternal(size_t num_bytes);
+  inline void WriteBytesCommon(const void* data, size_t length);
+
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, DeepCopyResize);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNext);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, PeekNextOverflow);
+  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/libchrome/base/pickle_unittest.cc b/libchrome/base/pickle_unittest.cc
new file mode 100644
index 0000000..e00edd9
--- /dev/null
+++ b/libchrome/base/pickle_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/pickle.h"
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/macros.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_t testuint16 = 32123;
+const uint32_t testuint32 = 1593847192;
+const int64_t testint64 = -0x7E8CA9253104BDFCLL;
+const uint64_t testuint64 = 0xCE8CA9253104BDF7ULL;
+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_t outuint16;
+  EXPECT_TRUE(iter.ReadUInt16(&outuint16));
+  EXPECT_EQ(testuint16, outuint16);
+
+  uint32_t outuint32;
+  EXPECT_TRUE(iter.ReadUInt32(&outuint32));
+  EXPECT_EQ(testuint32, outuint32);
+
+  int64_t outint64;
+  EXPECT_TRUE(iter.ReadInt64(&outint64));
+  EXPECT_EQ(testint64, outint64);
+
+  uint64_t outuint64;
+  EXPECT_TRUE(iter.ReadUInt64(&outuint64));
+  EXPECT_EQ(testuint64, outuint64);
+
+  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.WriteLong(testlong));
+  EXPECT_TRUE(pickle.WriteUInt16(testuint16));
+  EXPECT_TRUE(pickle.WriteUInt32(testuint32));
+  EXPECT_TRUE(pickle.WriteInt64(testint64));
+  EXPECT_TRUE(pickle.WriteUInt64(testuint64));
+  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 long 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, LongFrom64Bit) {
+  Pickle pickle;
+  // Under the hood long is always written as a 64-bit value, so simulate a
+  // 64-bit long even on 32-bit architectures by explicitly writing an int64_t.
+  EXPECT_TRUE(pickle.WriteInt64(testint64));
+
+  PickleIterator iter(pickle);
+  long outlong;
+  if (sizeof(long) < sizeof(int64_t)) {
+    // ReadLong() should return false when the original written value can't be
+    // represented as a long.
+#if GTEST_HAS_DEATH_TEST
+    EXPECT_DEATH(ignore_result(iter.ReadLong(&outlong)), "");
+#endif
+  } else {
+    EXPECT_TRUE(iter.ReadLong(&outlong));
+    EXPECT_EQ(testint64, outlong);
+  }
+}
+
+// Tests that we can handle really small buffers.
+TEST(PickleTest, SmallBuffer) {
+  std::unique_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, PeekNext) {
+  struct CustomHeader : base::Pickle::Header {
+    int cookies[10];
+  };
+
+  Pickle pickle(sizeof(CustomHeader));
+
+  EXPECT_TRUE(pickle.WriteString("Goooooooooooogle"));
+
+  const char* pickle_data = static_cast<const char*>(pickle.data());
+
+  size_t pickle_size;
+
+  // Data range doesn't contain header
+  EXPECT_FALSE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader) - 1,
+      &pickle_size));
+
+  // Data range contains header
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, pickle.size());
+
+  // Data range contains header and some other data
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader) + 1,
+      &pickle_size));
+  EXPECT_EQ(pickle_size, pickle.size());
+
+  // Data range contains full pickle
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + pickle.size(),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, pickle.size());
+}
+
+TEST(PickleTest, PeekNextOverflow) {
+  struct CustomHeader : base::Pickle::Header {
+    int cookies[10];
+  };
+
+  CustomHeader header;
+
+  // Check if we can wrap around at all
+  if (sizeof(size_t) > sizeof(header.payload_size))
+    return;
+
+  const char* pickle_data = reinterpret_cast<const char*>(&header);
+
+  size_t pickle_size;
+
+  // Wrapping around is detected and reported as maximum size_t value
+  header.payload_size = static_cast<uint32_t>(
+      1 - static_cast<int32_t>(sizeof(CustomHeader)));
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, std::numeric_limits<size_t>::max());
+
+  // Ridiculous pickle sizes are fine (callers are supposed to
+  // verify them)
+  header.payload_size =
+      std::numeric_limits<uint32_t>::max() / 2 - sizeof(CustomHeader);
+  EXPECT_TRUE(Pickle::PeekNext(
+      sizeof(CustomHeader),
+      pickle_data,
+      pickle_data + sizeof(CustomHeader),
+      &pickle_size));
+  EXPECT_EQ(pickle_size, std::numeric_limits<uint32_t>::max() / 2);
+}
+
+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);
+  std::unique_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;
+  std::unique_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;
+  std::unique_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_t);
+  Pickle pickle;
+  pickle.WriteData(
+      data_ptr, static_cast<int>(payload_size_after_header - sizeof(uint32_t)));
+  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_t)));
+  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_t 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_t>(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);
+}
+
+// Checks that when a pickle is deep-copied, the result is not larger than
+// needed.
+TEST(PickleTest, DeepCopyResize) {
+  Pickle pickle;
+  while (pickle.capacity_after_header() != pickle.payload_size())
+    pickle.WriteBool(true);
+
+  // Make a deep copy.
+  Pickle pickle2(pickle);
+
+  // Check that there isn't any extraneous capacity.
+  EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header());
+}
+
+namespace {
+
+// Publicly exposes the ClaimBytes interface for testing.
+class TestingPickle : public Pickle {
+ public:
+  TestingPickle() {}
+
+  void* ClaimBytes(size_t num_bytes) { return Pickle::ClaimBytes(num_bytes); }
+};
+
+}  // namespace
+
+// Checks that claimed bytes are zero-initialized.
+TEST(PickleTest, ClaimBytesInitialization) {
+  static const int kChunkSize = 64;
+  TestingPickle pickle;
+  const char* bytes = static_cast<const char*>(pickle.ClaimBytes(kChunkSize));
+  for (size_t i = 0; i < kChunkSize; ++i) {
+    EXPECT_EQ(0, bytes[i]);
+  }
+}
+
+// Checks that ClaimBytes properly advances the write offset.
+TEST(PickleTest, ClaimBytes) {
+  std::string data("Hello, world!");
+
+  TestingPickle pickle;
+  pickle.WriteUInt32(data.size());
+  void* bytes = pickle.ClaimBytes(data.size());
+  pickle.WriteInt(42);
+  memcpy(bytes, data.data(), data.size());
+
+  PickleIterator iter(pickle);
+  uint32_t out_data_length;
+  EXPECT_TRUE(iter.ReadUInt32(&out_data_length));
+  EXPECT_EQ(data.size(), out_data_length);
+
+  const char* out_data = nullptr;
+  EXPECT_TRUE(iter.ReadBytes(&out_data, out_data_length));
+  EXPECT_EQ(data, std::string(out_data, out_data_length));
+
+  int out_value;
+  EXPECT_TRUE(iter.ReadInt(&out_value));
+  EXPECT_EQ(42, out_value);
+}
+
+// Checks that PickleSizer and Pickle agree on the size of things.
+TEST(PickleTest, PickleSizer) {
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteBool(true);
+    sizer.AddBool();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteInt(42);
+    sizer.AddInt();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteLong(42);
+    sizer.AddLong();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteUInt16(42);
+    sizer.AddUInt16();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteUInt32(42);
+    sizer.AddUInt32();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteInt64(42);
+    sizer.AddInt64();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteUInt64(42);
+    sizer.AddUInt64();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteFloat(42.0f);
+    sizer.AddFloat();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteDouble(42.0);
+    sizer.AddDouble();
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteString(teststring);
+    sizer.AddString(teststring);
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteString16(teststring16);
+    sizer.AddString16(teststring16);
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteData(testdata, testdatalen);
+    sizer.AddData(testdatalen);
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+  {
+    TestingPickle pickle;
+    base::PickleSizer sizer;
+    pickle.WriteBytes(testdata, testdatalen);
+    sizer.AddBytes(testdatalen);
+    EXPECT_EQ(sizer.payload_size(), pickle.payload_size());
+  }
+}
+
+}  // namespace base
diff --git a/libchrome/base/posix/eintr_wrapper.h b/libchrome/base/posix/eintr_wrapper.h
new file mode 100644
index 0000000..5a5dc75
--- /dev/null
+++ b/libchrome/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/libchrome/base/posix/file_descriptor_shuffle.cc b/libchrome/base/posix/file_descriptor_shuffle.cc
new file mode 100644
index 0000000..d2fd39a
--- /dev/null
+++ b/libchrome/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/libchrome/base/posix/file_descriptor_shuffle.h b/libchrome/base/posix/file_descriptor_shuffle.h
new file mode 100644
index 0000000..78e3a7d
--- /dev/null
+++ b/libchrome/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/libchrome/base/posix/file_descriptor_shuffle_unittest.cc b/libchrome/base/posix/file_descriptor_shuffle_unittest.cc
new file mode 100644
index 0000000..3dfbf7e
--- /dev/null
+++ b/libchrome/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/libchrome/base/posix/global_descriptors.cc b/libchrome/base/posix/global_descriptors.cc
new file mode 100644
index 0000000..6c18783
--- /dev/null
+++ b/libchrome/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/libchrome/base/posix/global_descriptors.h b/libchrome/base/posix/global_descriptors.h
new file mode 100644
index 0000000..edb299d
--- /dev/null
+++ b/libchrome/base/posix/global_descriptors.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_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
+  // 3 used by __android_log_write().
+  // 4 used by... something important on Android M.
+  // 5 used by... something important on Android L... on low-end devices.
+  // TODO(amistry): An Android, this mechanism is only used for tests since the
+  // content child launcher spawns a process by creating a new Activity using
+  // the Android APIs. For tests, come up with a way that doesn't require using
+  // a pre-defined fd.
+  static const int kBaseDescriptor = 6;
+#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/libchrome/base/posix/safe_strerror.cc b/libchrome/base/posix/safe_strerror.cc
new file mode 100644
index 0000000..798658e
--- /dev/null
+++ b/libchrome/base/posix/safe_strerror.cc
@@ -0,0 +1,128 @@
+// 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 {
+
+#if defined(__GLIBC__) || defined(OS_NACL)
+#define USE_HISTORICAL_STRERRO_R 1
+#else
+#define USE_HISTORICAL_STRERRO_R 0
+#endif
+
+#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/libchrome/base/posix/safe_strerror.h b/libchrome/base/posix/safe_strerror.h
new file mode 100644
index 0000000..2945312
--- /dev/null
+++ b/libchrome/base/posix/safe_strerror.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_POSIX_SAFE_STRERROR_H_
+#define BASE_POSIX_SAFE_STRERROR_H_
+
+#include <stddef.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/libchrome/base/posix/unix_domain_socket_linux.cc b/libchrome/base/posix/unix_domain_socket_linux.cc
new file mode 100644
index 0000000..25ddb54
--- /dev/null
+++ b/libchrome/base/posix/unix_domain_socket_linux.cc
@@ -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.
+
+#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/pickle.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+#include "build/build_config.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;
+  memset(&msg, 0, sizeof(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,
+                                  std::vector<ScopedFD>* fds) {
+  return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
+                                         void* buf,
+                                         size_t length,
+                                         std::vector<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,
+                                           std::vector<ScopedFD>* fds,
+                                           ProcessId* out_pid) {
+  fds->clear();
+
+  struct msghdr msg;
+  memset(&msg, 0, sizeof(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(ScopedFD(wire_fds[i]));  // TODO(mdempsky): emplace_back
+  }
+
+  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();
+
+  std::vector<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/libchrome/base/posix/unix_domain_socket_linux.h b/libchrome/base/posix/unix_domain_socket_linux.h
new file mode 100644
index 0000000..2ba739e
--- /dev/null
+++ b/libchrome/base/posix/unix_domain_socket_linux.h
@@ -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.
+
+#ifndef BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+#define BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/files/scoped_file.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.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,
+                         std::vector<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,
+                                std::vector<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,
+                                  std::vector<ScopedFD>* fds,
+                                  ProcessId* pid);
+};
+
+}  // namespace base
+
+#endif  // BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
diff --git a/libchrome/base/posix/unix_domain_socket_linux_unittest.cc b/libchrome/base/posix/unix_domain_socket_linux_unittest.cc
new file mode 100644
index 0000000..3f5173c
--- /dev/null
+++ b/libchrome/base/posix/unix_domain_socket_linux_unittest.cc
@@ -0,0 +1,163 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#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/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.
+  std::vector<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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                      WaitableEvent::InitialState::NOT_SIGNALED);
+  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;
+  std::vector<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;
+  std::vector<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;
+  std::vector<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/libchrome/base/power_monitor/power_monitor.h b/libchrome/base/power_monitor/power_monitor.h
new file mode 100644
index 0000000..e025b32
--- /dev/null
+++ b/libchrome/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/macros.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(std::unique_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_;
+  std::unique_ptr<PowerMonitorSource> source_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_H_
diff --git a/libchrome/base/power_monitor/power_monitor_device_source.h b/libchrome/base/power_monitor/power_monitor_device_source.h
new file mode 100644
index 0000000..2dabac8
--- /dev/null
+++ b/libchrome/base/power_monitor/power_monitor_device_source.h
@@ -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.
+
+#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/macros.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"
+#include "build/build_config.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 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/libchrome/base/power_monitor/power_monitor_source.h b/libchrome/base/power_monitor/power_monitor_source.h
new file mode 100644
index 0000000..e63f4f8
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/power_monitor/power_observer.h b/libchrome/base/power_monitor/power_observer.h
new file mode 100644
index 0000000..6be70bb
--- /dev/null
+++ b/libchrome/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/libchrome/base/process/internal_linux.cc b/libchrome/base/process/internal_linux.cc
new file mode 100644
index 0000000..d286f4e
--- /dev/null
+++ b/libchrome/base/process/internal_linux.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <limits.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";
+
+FilePath GetProcPidDir(pid_t pid) {
+  return 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), " ",
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  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) {
+  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_t 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_t 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_t 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/libchrome/base/process/internal_linux.h b/libchrome/base/process/internal_linux.h
new file mode 100644
index 0000000..ba793f7
--- /dev/null
+++ b/libchrome/base/process/internal_linux.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.
+
+// 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 <stddef.h>
+#include <stdint.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_t 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_t 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/libchrome/base/process/kill.cc b/libchrome/base/process/kill.cc
new file mode 100644
index 0000000..5d8ba6a
--- /dev/null
+++ b/libchrome/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/libchrome/base/process/kill.h b/libchrome/base/process/kill.h
new file mode 100644
index 0000000..c664f33
--- /dev/null
+++ b/libchrome/base/process/kill.h
@@ -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.
+
+// 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"
+#include "build/build_config.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_LAUNCH_FAILED,        // child process never launched
+  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/libchrome/base/process/kill_posix.cc b/libchrome/base/process/kill_posix.cc
new file mode 100644
index 0000000..85470e0
--- /dev/null
+++ b/libchrome/base/process/kill_posix.cc
@@ -0,0 +1,232 @@
+// 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 <errno.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/macros.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"
+#include "build/build_config.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/libchrome/base/process/launch.cc b/libchrome/base/process/launch.cc
new file mode 100644
index 0000000..3ca5155
--- /dev/null
+++ b/libchrome/base/process/launch.cc
@@ -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.
+
+#include "base/process/launch.h"
+#include "build/build_config.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(const LaunchOptions& other) = default;
+
+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/libchrome/base/process/launch.h b/libchrome/base/process/launch.h
new file mode 100644
index 0000000..b8c0259
--- /dev/null
+++ b/libchrome/base/process/launch.h
@@ -0,0 +1,308 @@
+// 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 <stddef.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/environment.h"
+#include "base/macros.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.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(const LaunchOptions&);
+  ~LaunchOptions();
+
+  // If true, wait for the process to complete.
+  bool wait;
+
+  // If not empty, change to this directory before executing the new process.
+  base::FilePath current_directory;
+
+#if defined(OS_WIN)
+  bool start_hidden;
+
+  // If non-null, inherit exactly the list of handles in this vector (these
+  // handles must be inheritable).
+  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.
+  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 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)
+#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(bool create_console_if_not_found);
+#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);
+
+// Like GetAppOutput, but also includes stderr.
+BASE_EXPORT bool GetAppOutputAndError(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 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();
+#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) || defined(OS_NACL_NONSFI)
+// 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/libchrome/base/process/launch_mac.cc b/libchrome/base/process/launch_mac.cc
new file mode 100644
index 0000000..5895eae
--- /dev/null
+++ b/libchrome/base/process/launch_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/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);
+}
+
+}  // namespace base
diff --git a/libchrome/base/process/launch_posix.cc b/libchrome/base/process/launch_posix.cc
new file mode 100644
index 0000000..4fb1018
--- /dev/null
+++ b/libchrome/base/process/launch_posix.cc
@@ -0,0 +1,753 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.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 <memory>
+#include <set>
+
+#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/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 {
+
+#if !defined(OS_NACL_NONSFI)
+
+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) {
+#if defined(ANDROID)
+    struct kernel_sigaction act;
+    memset(&act, 0, sizeof(act));
+#else
+    struct kernel_sigaction act = {0};
+#endif
+    int sigaction_get_ret = sys_rt_sigaction(signum, nullptr, &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 = nullptr;
+      if (sys_rt_sigaction(signum, &act, nullptr)) {
+        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, nullptr, &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__))
+}  // anonymous namespace
+
+// Functor for |ScopedDIR| (below).
+struct ScopedDIRClose {
+  inline void operator()(DIR* x) const {
+    if (x)
+      closedir(x);
+  }
+};
+
+// Automatically closes |DIR*|s.
+typedef std::unique_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);
+
+  std::unique_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()] = nullptr;
+
+  std::unique_ptr<char* []> new_environ;
+  char* const empty_environ = nullptr;
+  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);
+      }
+    }
+
+    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();
+#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, nullptr)) == -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.
+}
+
+// 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. If |include_stderr| is true, includes stderr otherwise redirects
+// it to /dev/null.
+// The return value of the function indicates success or failure. In the case of
+// success, the application exit code will be returned in |*exit_code|, which
+// should be checked to determine if the application ran successfully.
+static bool GetAppOutputInternal(
+    const std::vector<std::string>& argv,
+    char* const envp[],
+    bool include_stderr,
+    std::string* 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;
+  std::unique_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 false;
+
+  switch (pid = fork()) {
+    case -1:  // error
+      close(pipe_fd[0]);
+      close(pipe_fd[1]);
+      return false;
+    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);
+
+        fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
+        fd_shuffle1.push_back(InjectionArc(
+            include_stderr ? pipe_fd[1] : 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()] = nullptr;
+        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();
+
+        while (true) {
+          char buffer[256];
+          ssize_t bytes_read =
+              HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer)));
+          if (bytes_read <= 0)
+            break;
+          output->append(buffer, bytes_read);
+        }
+        close(pipe_fd[0]);
+
+        // Always wait for exit code (even if we know we'll declare
+        // GOT_MAX_OUTPUT).
+        Process process(pid);
+        return process.WaitForExit(exit_code);
+      }
+  }
+}
+
+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.
+  int exit_code;
+  bool result =
+      GetAppOutputInternal(argv, nullptr, false, output, true, &exit_code);
+  return result && exit_code == EXIT_SUCCESS;
+}
+
+bool GetAppOutputAndError(const CommandLine& cl, std::string* output) {
+  // Run |execve()| with the current environment.
+  int exit_code;
+  bool result =
+      GetAppOutputInternal(cl.argv(), nullptr, true, output, true, &exit_code);
+  return result && exit_code == EXIT_SUCCESS;
+}
+
+bool GetAppOutputWithExitCode(const CommandLine& cl,
+                              std::string* output,
+                              int* exit_code) {
+  // Run |execve()| with the current environment.
+  return GetAppOutputInternal(cl.argv(), nullptr, false, output, true,
+                              exit_code);
+}
+
+#endif  // !defined(OS_NACL_NONSFI)
+
+#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
+namespace {
+
+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] ALIGNAS(16);
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_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);
+}
+
+}  // anonymous namespace
+
+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)
+    // 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) || defined(OS_NACL_NONSFI)
+
+}  // namespace base
diff --git a/libchrome/base/process/port_provider_mac.cc b/libchrome/base/process/port_provider_mac.cc
new file mode 100644
index 0000000..ac13949
--- /dev/null
+++ b/libchrome/base/process/port_provider_mac.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/process/port_provider_mac.h"
+
+namespace base {
+
+PortProvider::PortProvider() : lock_(), observer_list_() {}
+PortProvider::~PortProvider() {}
+
+void PortProvider::AddObserver(Observer* observer) {
+  base::AutoLock l(lock_);
+  observer_list_.AddObserver(observer);
+}
+
+void PortProvider::RemoveObserver(Observer* observer) {
+  base::AutoLock l(lock_);
+  observer_list_.RemoveObserver(observer);
+}
+
+void PortProvider::NotifyObservers(ProcessHandle process) {
+  base::AutoLock l(lock_);
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnReceivedTaskPort(process));
+}
+
+}  // namespace base
diff --git a/libchrome/base/process/port_provider_mac.h b/libchrome/base/process/port_provider_mac.h
new file mode 100644
index 0000000..2f40297
--- /dev/null
+++ b/libchrome/base/process/port_provider_mac.h
@@ -0,0 +1,61 @@
+// 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_PROCESS_PORT_PROVIDER_MAC_H_
+#define BASE_PROCESS_PORT_PROVIDER_MAC_H_
+
+#include <mach/mach.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// Abstract base class that provides a mapping from ProcessHandle (pid_t) to the
+// Mach task port. This replicates task_for_pid(), which requires root
+// privileges.
+class BASE_EXPORT PortProvider {
+ public:
+  PortProvider();
+  virtual ~PortProvider();
+
+  class Observer {
+   public:
+    virtual ~Observer() {};
+    // Called by the PortProvider to notify observers that the task port was
+    // received for a given process.
+    // No guarantees are made about the thread on which this notification will
+    // be sent.
+    // Observers must not call AddObserver() or RemoveObserver() in this
+    // callback, as doing so will deadlock.
+    virtual void OnReceivedTaskPort(ProcessHandle process) = 0;
+  };
+
+  // Returns the mach task port for |process| if possible, or else
+  // |MACH_PORT_NULL|.
+  virtual mach_port_t TaskForPid(ProcessHandle process) const = 0;
+
+  // Observer interface.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+ protected:
+  // Called by subclasses to send a notification to observers.
+  void NotifyObservers(ProcessHandle process);
+
+ private:
+  // ObserverList is not thread-safe, so |lock_| ensures consistency of
+  // |observer_list_|.
+  base::Lock lock_;
+  base::ObserverList<Observer> observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(PortProvider);
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PORT_PROVIDER_MAC_H_
diff --git a/libchrome/base/process/process.h b/libchrome/base/process/process.h
new file mode 100644
index 0000000..70c8260
--- /dev/null
+++ b/libchrome/base/process/process.h
@@ -0,0 +1,151 @@
+// 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/macros.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 {
+ public:
+  explicit Process(ProcessHandle handle = kNullProcessHandle);
+
+  Process(Process&& other);
+
+  // The destructor does not terminate the process.
+  ~Process();
+
+  Process& operator=(Process&& 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);
+
+  // 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);
+
+  // Returns an integer representing the priority of a process. The meaning
+  // of this value is OS dependent.
+  int GetPriority() const;
+
+#if defined(OS_CHROMEOS)
+  // Get the PID in its PID namespace.
+  // If the process is not in a PID namespace or /proc/<pid>/status does not
+  // report NSpid, kNullProcessId is returned.
+  ProcessId GetPidInNamespace() const;
+#endif
+
+ private:
+#if defined(OS_WIN)
+  bool is_current_process_;
+  win::ScopedHandle process_;
+#else
+  ProcessHandle process_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(Process);
+};
+
+#if defined(OS_CHROMEOS)
+// Exposed for testing.
+// Given the contents of the /proc/<pid>/cgroup file, determine whether the
+// process is backgrounded or not.
+BASE_EXPORT bool IsProcessBackgroundedCGroup(
+    const StringPiece& cgroup_contents);
+#endif  // defined(OS_CHROMEOS)
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_H_
diff --git a/libchrome/base/process/process_handle.cc b/libchrome/base/process/process_handle.cc
new file mode 100644
index 0000000..1f22b93
--- /dev/null
+++ b/libchrome/base/process/process_handle.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 <stdint.h>
+
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+bool g_have_unique_id = false;
+uint32_t g_unique_id;
+
+// The process which set |g_unique_id|.
+ProcessId g_procid;
+
+// Mangle IDs so that they are not accidentally used as PIDs, e.g. as an
+// argument to kill or waitpid.
+uint32_t MangleProcessId(ProcessId process_id) {
+  // Add a large power of 10 so that the pid is still the pid is still readable
+  // inside the mangled id.
+  return static_cast<uint32_t>(process_id) + 1000000000U;
+}
+
+}  // namespace
+
+uint32_t GetUniqueIdForProcess() {
+  if (!g_have_unique_id) {
+    return MangleProcessId(GetCurrentProcId());
+  }
+
+  // Make sure we are the same process that set |g_procid|. This check may have
+  // false negatives (if a process ID was reused) but should have no false
+  // positives.
+  DCHECK_EQ(GetCurrentProcId(), g_procid);
+  return g_unique_id;
+}
+
+#if defined(OS_LINUX)
+
+void InitUniqueIdForProcessInPidNamespace(ProcessId pid_outside_of_namespace) {
+  g_unique_id = MangleProcessId(pid_outside_of_namespace);
+  g_procid = GetCurrentProcId();
+  g_have_unique_id = true;
+}
+
+#endif
+
+}  // namespace base
diff --git a/libchrome/base/process/process_handle.h b/libchrome/base/process/process_handle.h
new file mode 100644
index 0000000..ef7a602
--- /dev/null
+++ b/libchrome/base/process/process_handle.h
@@ -0,0 +1,81 @@
+// 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 <stdint.h>
+#include <sys/types.h>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "build/build_config.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.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes (use GetUniqueIdForProcess if uniqueness is required).
+BASE_EXPORT ProcessId GetCurrentProcId();
+
+// Returns a unique ID for the current process. The ID will be unique across all
+// currently running processes within the chrome session, but IDs of terminated
+// processes may be reused. This returns an opaque value that is different from
+// a process's PID.
+BASE_EXPORT uint32_t GetUniqueIdForProcess();
+
+#if defined(OS_LINUX)
+// When a process is started in a different PID namespace from the browser
+// process, this function must be called with the process's PID in the browser's
+// PID namespace in order to initialize its unique ID. Not thread safe.
+// WARNING: To avoid inconsistent results from GetUniqueIdForProcess, this
+// should only be called very early after process startup - ideally as soon
+// after process creation as possible.
+BASE_EXPORT void InitUniqueIdForProcessInPidNamespace(
+    ProcessId pid_outside_of_namespace);
+#endif
+
+// Returns the ProcessHandle of the current process.
+BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
+
+// Returns the process 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.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes.
+BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
+
+// Returns the ID for the parent of the given process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+
+#if defined(OS_POSIX)
+// Returns the path to the executable of the given process.
+BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_HANDLE_H_
diff --git a/libchrome/base/process/process_handle_linux.cc b/libchrome/base/process/process_handle_linux.cc
new file mode 100644
index 0000000..950b888
--- /dev/null
+++ b/libchrome/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/libchrome/base/process/process_handle_mac.cc b/libchrome/base/process/process_handle_mac.cc
new file mode 100644
index 0000000..d9d22f7
--- /dev/null
+++ b/libchrome/base/process/process_handle_mac.cc
@@ -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.
+
+#include "base/process/process_handle.h"
+
+#include <libproc.h>
+#include <stddef.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/libchrome/base/process/process_handle_posix.cc b/libchrome/base/process/process_handle_posix.cc
new file mode 100644
index 0000000..4e332df
--- /dev/null
+++ b/libchrome/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/libchrome/base/process/process_info.h b/libchrome/base/process/process_info.h
new file mode 100644
index 0000000..1d76f42
--- /dev/null
+++ b/libchrome/base/process/process_info.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_PROCESS_PROCESS_INFO_H_
+#define BASE_PROCESS_PROCESS_INFO_H_
+
+#include "base/base_export.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/libchrome/base/process/process_iterator.cc b/libchrome/base/process/process_iterator.cc
new file mode 100644
index 0000000..d4024d9
--- /dev/null
+++ b/libchrome/base/process/process_iterator.cc
@@ -0,0 +1,67 @@
+// 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 "build/build_config.h"
+
+namespace base {
+
+#if defined(OS_POSIX)
+ProcessEntry::ProcessEntry() : pid_(0), ppid_(0), gid_(0) {}
+ProcessEntry::ProcessEntry(const ProcessEntry& other) = default;
+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/libchrome/base/process/process_iterator.h b/libchrome/base/process/process_iterator.h
new file mode 100644
index 0000000..0d1f1a6
--- /dev/null
+++ b/libchrome/base/process/process_iterator.h
@@ -0,0 +1,151 @@
+// 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 <stddef.h>
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/macros.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(const ProcessEntry& other);
+  ~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/libchrome/base/process/process_iterator_linux.cc b/libchrome/base/process/process_iterator_linux.cc
new file mode 100644
index 0000000..421565f
--- /dev/null
+++ b/libchrome/base/process/process_iterator_linux.cc
@@ -0,0 +1,151 @@
+// 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 <stddef.h>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/strings/string_split.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');
+  *proc_cmd_line_args = SplitString(cmd_line, delimiters, KEEP_WHITESPACE,
+                                    SPLIT_WANT_NONEMPTY);
+  return true;
+}
+
+}  // namespace
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : filter_(filter) {
+  procfs_dir_ = opendir(internal::kProcDir);
+  if (!procfs_dir_) {
+    // On Android, SELinux may prevent reading /proc. See
+    // https://crbug.com/581517 for details.
+    PLOG(ERROR) << "opendir " << internal::kProcDir;
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+  if (procfs_dir_) {
+    closedir(procfs_dir_);
+    procfs_dir_ = nullptr;
+  }
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  // TODO(port): skip processes owned by different UID
+
+  if (!procfs_dir_) {
+    DLOG(ERROR) << "Skipping CheckForNextProcess(), no procfs_dir_";
+    return false;
+  }
+
+  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/libchrome/base/process/process_iterator_mac.cc b/libchrome/base/process/process_iterator_mac.cc
new file mode 100644
index 0000000..3d61698
--- /dev/null
+++ b/libchrome/base/process/process_iterator_mac.cc
@@ -0,0 +1,140 @@
+// 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 <stddef.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_split.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,
+                static_cast<int>(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');
+    entry_.cmd_line_args_ = SplitString(data, delimiters,
+                                        KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+
+    // |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/libchrome/base/process/process_metrics.cc b/libchrome/base/process/process_metrics.cc
new file mode 100644
index 0000000..0b38726
--- /dev/null
+++ b/libchrome/base/process/process_metrics.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/process/process_metrics.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/values.h"
+#include "build/build_config.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;
+}
+
+std::unique_ptr<Value> SystemMetrics::ToValue() const {
+  std::unique_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 std::move(res);
+}
+
+ProcessMetrics* ProcessMetrics::CreateCurrentProcessMetrics() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  return CreateProcessMetrics(base::GetCurrentProcessHandle());
+#else
+  return CreateProcessMetrics(base::GetCurrentProcessHandle(), nullptr);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+}
+
+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_t 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_t wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_;
+  int64_t 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_t 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/libchrome/base/process/process_metrics.h b/libchrome/base/process/process_metrics.h
new file mode 100644
index 0000000..e67b663
--- /dev/null
+++ b/libchrome/base/process/process_metrics.h
@@ -0,0 +1,462 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#include "base/process/port_provider_mac.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_t TimeValToMicroseconds(const struct timeval& tv);
+
+// A callback to filter threads of a process (when counting CPU time)
+using ThreadFilterCb = std::function<bool(const std::string &stat)>;
+
+// Provides performance metrics for a specified process (CPU usage, memory and
+// IO counters). Use CreateCurrentProcessMetrics() to get an instance for the
+// current process, or CreateProcessMetrics() to get an instance for an
+// arbitrary 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);
+
+  static ProcessMetrics* CreateProcessMetricsWithFilter(ProcessHandle process,
+      ThreadFilterCb thread_filter);
+#else
+
+  // 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)
+
+  // Creates a ProcessMetrics for the current process. This a cross-platform
+  // convenience wrapper for CreateProcessMetrics().
+  // The caller owns the returned object.
+  static ProcessMetrics* CreateCurrentProcessMetrics();
+
+  // 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. Note that this
+  // function is somewhat expensive on Windows (a few ms per process).
+  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;
+
+#if defined(OS_LINUX)
+  // Returns the number of file descriptors currently open by the process, or
+  // -1 on error.
+  int GetOpenFdCount() const;
+#endif  // defined(OS_LINUX)
+
+ private:
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  explicit ProcessMetrics(ProcessHandle process, ThreadFilterCb thread_filter);
+#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_t 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_t last_system_time_;
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+  // Same thing for idle wakeups.
+  TimeTicks last_idle_wakeups_time_;
+  uint64_t 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)
+
+  ThreadFilterCb thread_filter_;
+
+  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. Do not use this to compute
+// the number of pages in a block of memory for calling mincore(). On some
+// platforms, e.g. iOS, mincore() uses a different page size from what is
+// returned by GetPageSize().
+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_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
+    defined(OS_ANDROID)
+// Data about system-wide memory consumption. Values are in KB. Available on
+// Windows, Mac, Linux, Android and Chrome OS.
+//
+// Total/free memory are available on all platforms that implement
+// GetSystemMemoryInfo(). Total/free swap memory are available on all platforms
+// except on Mac. Buffers/cached/active_anon/inactive_anon/active_file/
+// inactive_file/dirty/pswpin/pswpout/pgmajfault are available on
+// Linux/Android/Chrome OS. Shmem/slab/gem_objects/gem_size are Chrome OS only.
+struct BASE_EXPORT SystemMemoryInfoKB {
+  SystemMemoryInfoKB();
+  SystemMemoryInfoKB(const SystemMemoryInfoKB& other);
+
+  // Serializes the platform specific fields to value.
+  std::unique_ptr<Value> ToValue() const;
+
+  int total;
+  int free;
+
+#if defined(OS_LINUX)
+  // This provides an estimate of available memory as described here:
+  // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
+  // NOTE: this is ONLY valid in kernels 3.14 and up.  Its value will always
+  // be 0 in earlier kernel versions.
+  int available;
+#endif
+
+#if !defined(OS_MACOSX)
+  int swap_total;
+  int swap_free;
+#endif
+
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+  int buffers;
+  int cached;
+  int active_anon;
+  int inactive_anon;
+  int active_file;
+  int inactive_file;
+  int dirty;
+
+  // vmstats data.
+  int pswpin;
+  int pswpout;
+  int pgmajfault;
+#endif  // defined(OS_ANDROID) || defined(OS_LINUX)
+
+#if defined(OS_CHROMEOS)
+  int shmem;
+  int slab;
+  // Gem data will be -1 if not supported.
+  int gem_objects;
+  long long gem_size;
+#endif  // defined(OS_CHROMEOS)
+};
+
+// On Linux/Android/Chrome OS, system-wide memory consumption data is parsed
+// from /proc/meminfo and /proc/vmstat. On Windows/Mac, it is obtained using
+// system API calls.
+//
+// Fills in the provided |meminfo| structure. Returns true on success.
+// Exposed for memory debugging widget.
+BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo);
+
+#endif  // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
+        // defined(OS_ANDROID)
+
+#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[];
+
+// 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);
+
+// Data from /proc/diskstats about system-wide disk I/O.
+struct BASE_EXPORT SystemDiskInfo {
+  SystemDiskInfo();
+  SystemDiskInfo(const SystemDiskInfo& other);
+
+  // Serializes the platform specific fields to value.
+  std::unique_ptr<Value> ToValue() const;
+
+  uint64_t reads;
+  uint64_t reads_merged;
+  uint64_t sectors_read;
+  uint64_t read_time;
+  uint64_t writes;
+  uint64_t writes_merged;
+  uint64_t sectors_written;
+  uint64_t write_time;
+  uint64_t io;
+  uint64_t io_time;
+  uint64_t 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.
+  std::unique_ptr<Value> ToValue() const;
+
+  uint64_t num_reads;
+  uint64_t num_writes;
+  uint64_t compr_data_size;
+  uint64_t orig_data_size;
+  uint64_t 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)
+
+class SystemCpuMetrics {
+ public:
+  SystemCpuMetrics();
+
+  // 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();
+
+ private:
+  // Used to store the previous times and CPU usage counts so we can
+  // compute the CPU usage between calls.
+  TimeTicks last_cpu_time_;
+
+  // Jiffie count at the last_cpu_time_ we updated.
+  int last_cpu_;
+
+};
+
+// 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.
+  std::unique_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/libchrome/base/process/process_metrics_linux.cc b/libchrome/base/process/process_metrics_linux.cc
new file mode 100644
index 0000000..146bbc5
--- /dev/null
+++ b/libchrome/base/process/process_metrics_linux.cc
@@ -0,0 +1,1072 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utility>
+
+#include "base/files/dir_reader_posix.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"
+#include "build/build_config.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_t.
+static uint64_t 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_t 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<StringPiece> split_value_str = SplitStringPiece(
+          value_str, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+      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;
+    }
+  }
+  // This can be reached if the process dies when proc is read -- in that case,
+  // the kernel can return missing fields.
+  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_t* 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_t value;
+      if (!StringToUint64(value_str, &value))
+        return false;
+      *result = value;
+      return true;
+    }
+  }
+  return false;
+}
+#endif  // defined(OS_LINUX)
+
+typedef std::map<std::string, std::string> ProcStatMap;
+
+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();
+}
+
+void ParseProcStat(const std::string& contents, ProcStatMap* output) {
+  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]);
+  }
+}
+
+int GetSystemCpuTimeSinceBoot() {
+  FilePath path("/proc/stat");
+  std::string contents;
+  if (!ReadProcFile(path, &contents))
+    return 0;
+
+  ProcStatMap proc_stat;
+  ParseProcStat(contents, &proc_stat);
+  ProcStatMap::const_iterator cpu_it = proc_stat.find("cpu");
+  if (cpu_it == proc_stat.end())
+    return 0;
+
+  std::vector<std::string> cpu = SplitString(
+      cpu_it->second, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+
+  uint64_t user;
+  uint64_t nice;
+  uint64_t system;
+  if (!StringToUint64(cpu[0], &user) || !StringToUint64(cpu[1], &nice) || !StringToUint64(cpu[2], &system))
+    return 0;
+
+    return user + nice + system;
+}
+
+// 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, ThreadFilterCb thread_filter) {
+  // 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)) {
+      // Only include threads for which the filter returns true
+      if (thread_filter && !thread_filter(stat)) {
+        continue;
+      }
+
+      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, ThreadFilterCb());
+}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetricsWithFilter(
+    ProcessHandle process, ThreadFilterCb thread_filter)
+{
+  return new ProcessMetrics(process, thread_filter);
+}
+
+// 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);
+}
+
+SystemCpuMetrics::SystemCpuMetrics() {
+  last_cpu_ = 0;
+}
+
+double SystemCpuMetrics::GetCPUUsage() {
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_cpu_ == 0) {
+    // First call, just set the last values.
+    last_cpu_time_ = time;
+    last_cpu_ = GetSystemCpuTimeSinceBoot();
+    return 0.0;
+  }
+
+  TimeDelta time_delta = time - last_cpu_time_;
+  if (time_delta.is_zero()) {
+    NOTREACHED();
+    return 0.0;
+  }
+
+  int cpu = GetSystemCpuTimeSinceBoot();
+
+  // 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_);
+
+  // If the number of threads running in the process has decreased since the
+  // last time this function was called, |last_cpu_time| will be greater than
+  // |cpu_time| which will result in a negative value in the below percentage
+  // calculation. We prevent this by clamping to 0. crbug.com/546565.
+  // This computation is known to be shaky when threads are destroyed between
+  // "last" and "now", but for our current purposes, it's all right.
+  double percentage = 0.0;
+  if (last_cpu_time < cpu_time) {
+    percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
+        time_delta.InSecondsF();
+  }
+
+  last_cpu_time_ = time;
+  last_cpu_ = cpu;
+
+  return percentage;
+}
+
+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_, thread_filter_);
+    return 0.0;
+  }
+
+  TimeDelta time_delta = time - last_cpu_time_;
+  if (time_delta.is_zero()) {
+    NOTREACHED();
+    return 0.0;
+  }
+
+  int cpu = GetProcessCPU(process_, thread_filter_);
+
+  // 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_);
+
+  // If the number of threads running in the process has decreased since the
+  // last time this function was called, |last_cpu_time| will be greater than
+  // |cpu_time| which will result in a negative value in the below percentage
+  // calculation. We prevent this by clamping to 0. crbug.com/546565.
+  // This computation is known to be shaky when threads are destroyed between
+  // "last" and "now", but for our current purposes, it's all right.
+  double percentage = 0.0;
+  if (last_cpu_time < cpu_time) {
+    percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
+        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_t* 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;
+}
+
+#if defined(OS_LINUX)
+int ProcessMetrics::GetOpenFdCount() const {
+  // Use /proc/<pid>/fd to count the number of entries there.
+  FilePath fd_path = internal::GetProcPidDir(process_).Append("fd");
+
+  DirReaderPosix dir_reader(fd_path.value().c_str());
+  if (!dir_reader.IsValid())
+    return -1;
+
+  int total_count = 0;
+  for (; dir_reader.Next(); ) {
+    const char* name = dir_reader.name();
+    if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
+      ++total_count;
+  }
+
+  return total_count;
+}
+#endif  // defined(OS_LINUX)
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process,
+    ThreadFilterCb thread_filter)
+    : process_(process),
+      last_system_time_(0),
+#if defined(OS_LINUX)
+      last_absolute_idle_wakeups_(0),
+#endif
+      last_cpu_(0),
+      thread_filter_(thread_filter) {
+  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 = SplitString(
+      totmaps_data, base::kWhitespaceASCII, base::KEEP_WHITESPACE,
+      base::SPLIT_WANT_NONEMPTY);
+
+  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<StringPiece> statm_vec = SplitStringPiece(
+      statm, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  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;
+#if defined(OS_LINUX)
+  available = 0;
+#endif
+  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
+}
+
+SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) =
+    default;
+
+std::unique_ptr<Value> SystemMemoryInfoKB::ToValue() const {
+  std::unique_ptr<DictionaryValue> res(new DictionaryValue());
+
+  res->SetInteger("total", total);
+  res->SetInteger("free", free);
+#if defined(OS_LINUX)
+  res->SetInteger("available", available);
+#endif
+  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 std::move(res);
+}
+
+// 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;
+
+  for (const StringPiece& line : SplitStringPiece(
+           meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+    std::vector<StringPiece> tokens = SplitStringPiece(
+        line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+    // 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: " << line.as_string();
+      continue;
+    }
+
+    int* target = NULL;
+    if (tokens[0] == "MemTotal:")
+      target = &meminfo->total;
+    else if (tokens[0] == "MemFree:")
+      target = &meminfo->free;
+#if defined(OS_LINUX)
+    else if (tokens[0] == "MemAvailable:")
+      target = &meminfo->available;
+#endif
+    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.
+
+  for (const StringPiece& line : SplitStringPiece(
+           vmstat_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
+    std::vector<StringPiece> tokens = SplitStringPiece(
+        line, " ", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+    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;
+}
+
+SystemDiskInfo::SystemDiskInfo(const SystemDiskInfo& other) = default;
+
+std::unique_ptr<Value> SystemDiskInfo::ToValue() const {
+  std::unique_ptr<DictionaryValue> res(new DictionaryValue());
+
+  // Write out uint64_t 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 std::move(res);
+}
+
+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<StringPiece> diskinfo_lines = SplitStringPiece(
+      diskinfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  if (diskinfo_lines.size() == 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_t reads = 0;
+  uint64_t reads_merged = 0;
+  uint64_t sectors_read = 0;
+  uint64_t read_time = 0;
+  uint64_t writes = 0;
+  uint64_t writes_merged = 0;
+  uint64_t sectors_written = 0;
+  uint64_t write_time = 0;
+  uint64_t io = 0;
+  uint64_t io_time = 0;
+  uint64_t weighted_io_time = 0;
+
+  for (const StringPiece& line : diskinfo_lines) {
+    std::vector<StringPiece> disk_fields = SplitStringPiece(
+        line, kWhitespaceASCII, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+
+    // Fields may have overflowed and reset to zero.
+    if (IsValidDiskName(disk_fields[kDiskDriveName].as_string())) {
+      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)
+std::unique_ptr<Value> SwapInfo::ToValue() const {
+  std::unique_ptr<DictionaryValue> res(new DictionaryValue());
+
+  // Write out uint64_t 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 std::move(res);
+}
+
+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_t 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_t 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/libchrome/base/process/process_metrics_mac.cc b/libchrome/base/process/process_metrics_mac.cc
new file mode 100644
index 0000000..8b5d564
--- /dev/null
+++ b/libchrome/base/process/process_metrics_mac.cc
@@ -0,0 +1,399 @@
+// 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 <stddef.h>
+#include <stdint.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
+
+SystemMemoryInfoKB::SystemMemoryInfoKB() {
+  total = 0;
+  free = 0;
+}
+
+SystemMemoryInfoKB::SystemMemoryInfoKB(const SystemMemoryInfoKB& other) =
+    default;
+
+// 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,
+    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_t 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_t system_time_delta = task_time - last_system_time_;
+  int64_t 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,
+                               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.get(), 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;
+}
+
+// On Mac, We only get total memory and free memory from the system.
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+  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.get(), HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo), &count);
+  if (result != KERN_SUCCESS)
+    return false;
+
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  meminfo->total = static_cast<int>(hostinfo.max_mem / 1024);
+
+  vm_statistics_data_t vm_info;
+  count = HOST_VM_INFO_COUNT;
+
+  if (host_statistics(host.get(), HOST_VM_INFO,
+                      reinterpret_cast<host_info_t>(&vm_info),
+                      &count) != KERN_SUCCESS) {
+    return false;
+  }
+
+  meminfo->free = static_cast<int>(
+      (vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE / 1024);
+
+  return true;
+}
+
+}  // namespace base
diff --git a/libchrome/base/process/process_metrics_posix.cc b/libchrome/base/process/process_metrics_posix.cc
new file mode 100644
index 0000000..fad581e
--- /dev/null
+++ b/libchrome/base/process/process_metrics_posix.cc
@@ -0,0 +1,80 @@
+// 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 <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace base {
+
+int64_t TimeValToMicroseconds(const struct timeval& tv) {
+  int64_t 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/libchrome/base/process/process_metrics_unittest.cc b/libchrome/base/process/process_metrics_unittest.cc
new file mode 100644
index 0000000..94a2ffe
--- /dev/null
+++ b/libchrome/base/process/process_metrics_unittest.cc
@@ -0,0 +1,519 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <sstream>
+#include <string>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/multiprocess_test.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+namespace debug {
+
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+namespace {
+
+void BusyWork(std::vector<std::string>* vec) {
+  int64_t test_value = 0;
+  for (int i = 0; i < 100000; ++i) {
+    ++test_value;
+    vec->push_back(Int64ToString(test_value));
+  }
+}
+
+}  // namespace
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
+
+// 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_CHROMEOS)
+
+// Test that ProcessMetrics::GetCPUUsage() doesn't return negative values when
+// the number of threads running on the process decreases between two successive
+// calls to it.
+TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
+  ProcessHandle handle = GetCurrentProcessHandle();
+  std::unique_ptr<ProcessMetrics> metrics(
+      ProcessMetrics::CreateProcessMetrics(handle));
+
+  EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+  Thread thread1("thread1");
+  Thread thread2("thread2");
+  Thread thread3("thread3");
+
+  thread1.StartAndWaitForTesting();
+  thread2.StartAndWaitForTesting();
+  thread3.StartAndWaitForTesting();
+
+  ASSERT_TRUE(thread1.IsRunning());
+  ASSERT_TRUE(thread2.IsRunning());
+  ASSERT_TRUE(thread3.IsRunning());
+
+  std::vector<std::string> vec1;
+  std::vector<std::string> vec2;
+  std::vector<std::string> vec3;
+
+  thread1.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec1));
+  thread2.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec2));
+  thread3.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec3));
+
+  EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+  thread1.Stop();
+  EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+  thread2.Stop();
+  EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+  thread3.Stop();
+  EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+}
+
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
+
+#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
+    defined(OS_LINUX) || defined(OS_ANDROID)
+TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
+  SystemMemoryInfoKB info;
+  EXPECT_TRUE(GetSystemMemoryInfo(&info));
+
+  // Ensure each field received a value.
+  EXPECT_GT(info.total, 0);
+  EXPECT_GT(info.free, 0);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  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);
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+  // All the values should be less than the total amount of memory.
+  EXPECT_LT(info.free, info.total);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  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);
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#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_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) ||
+        // 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, 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, 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, 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 ProcessHandle current = GetCurrentProcessHandle();
+  const int initial_threads = GetNumberOfThreads(current);
+  ASSERT_GT(initial_threads, 0);
+  const int kNumAdditionalThreads = 10;
+  {
+    std::unique_ptr<Thread> my_threads[kNumAdditionalThreads];
+    for (int i = 0; i < kNumAdditionalThreads; ++i) {
+      my_threads[i].reset(new Thread("GetNumberOfThreadsTest"));
+      my_threads[i]->Start();
+      ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i);
+    }
+  }
+  // The Thread destructor will stop them.
+  ASSERT_EQ(initial_threads, GetNumberOfThreads(current));
+}
+#endif  // defined(OS_LINUX)
+
+#if defined(OS_LINUX)
+namespace {
+
+// Keep these in sync so the GetOpenFdCount test can refer to correct test main.
+#define ChildMain ChildFdCount
+#define ChildMainString "ChildFdCount"
+
+// Command line flag name and file name used for synchronization.
+const char kTempDirFlag[] = "temp-dir";
+const char kSignalClosed[] = "closed";
+
+bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
+  File file(signal_dir.AppendASCII(signal_file),
+            File::FLAG_CREATE | File::FLAG_WRITE);
+  return file.IsValid();
+}
+
+// Check whether an event was signaled.
+bool CheckEvent(const FilePath& signal_dir, const char* signal_file) {
+  File file(signal_dir.AppendASCII(signal_file),
+            File::FLAG_OPEN | File::FLAG_READ);
+  return file.IsValid();
+}
+
+// Busy-wait for an event to be signaled.
+void WaitForEvent(const FilePath& signal_dir, const char* signal_file) {
+  while (!CheckEvent(signal_dir, signal_file))
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+}
+
+// Subprocess to test the number of open file descriptors.
+MULTIPROCESS_TEST_MAIN(ChildMain) {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
+  CHECK(DirectoryExists(temp_path));
+
+  // Try to close all the file descriptors, so the open count goes to 0.
+  for (size_t i = 0; i < 1000; ++i)
+    close(i);
+  CHECK(SignalEvent(temp_path, kSignalClosed));
+
+  // Wait to be terminated.
+  while (true)
+    PlatformThread::Sleep(TimeDelta::FromSeconds(1));
+  return 0;
+}
+
+}  // namespace
+
+TEST(ProcessMetricsTest, GetOpenFdCount) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const FilePath temp_path = temp_dir.path();
+  CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
+  child_command_line.AppendSwitchPath(kTempDirFlag, temp_path);
+  Process child = SpawnMultiProcessTestChild(
+      ChildMainString, child_command_line, LaunchOptions());
+  ASSERT_TRUE(child.IsValid());
+  WaitForEvent(temp_path, kSignalClosed);
+
+  std::unique_ptr<ProcessMetrics> metrics(
+      ProcessMetrics::CreateProcessMetrics(child.Handle()));
+  // Try a couple times to observe the child with 0 fds open.
+  // Sometimes we've seen that the child can have 1 remaining
+  // fd shortly after receiving the signal.  Potentially this
+  // is actually the signal file still open in the child.
+  int open_fds = -1;
+  for (int tries = 0; tries < 5; ++tries) {
+    open_fds = metrics->GetOpenFdCount();
+    if (!open_fds) {
+      break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+  }
+  EXPECT_EQ(0, open_fds);
+  ASSERT_TRUE(child.Terminate(0, true));
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace debug
+}  // namespace base
diff --git a/libchrome/base/process/process_posix.cc b/libchrome/base/process/process_posix.cc
new file mode 100644
index 0000000..ba9b544
--- /dev/null
+++ b/libchrome/base/process/process_posix.cc
@@ -0,0 +1,385 @@
+// 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 <errno.h>
+#include <stdint.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"
+#include "build/build_config.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_t kMaxSleepInMicroseconds = 1 << 18;  // ~256 milliseconds.
+  int64_t max_sleep_time_usecs = 1 << 10;                  // ~1 milliseconds.
+  int64_t 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_t 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;
+  }
+
+#if defined(ANDROID)
+  struct kevent change;
+  memset(&change, 0, sizeof(change));
+#else
+  struct kevent change = {0};
+#endif
+  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;
+#if defined(ANDROID)
+  struct kevent event;
+  memset(&event, 0, sizeof(event));
+#else
+  struct kevent event = {0};
+#endif
+
+  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(Process&& other) : process_(other.process_) {
+  other.Close();
+}
+
+Process& Process::operator=(Process&& other) {
+  DCHECK_NE(this, &other);
+  process_ = other.process_;
+  other.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)
+// static
+bool Process::CanBackgroundProcesses() {
+  return false;
+}
+#endif  // !defined(OS_LINUX)
+
+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 {
+  // exit_code isn't supportable.
+  DCHECK(IsValid());
+  CHECK_GT(process_, 0);
+
+  bool result = kill(process_, SIGTERM) == 0;
+  if (result && wait) {
+    int tries = 60;
+
+    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)
+bool Process::IsProcessBackgrounded() const {
+  // See SetProcessBackgrounded().
+  DCHECK(IsValid());
+  return false;
+}
+
+bool Process::SetProcessBackgrounded(bool /*value*/) {
+  // Not implemented for POSIX systems other than 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)
+
+int Process::GetPriority() const {
+  DCHECK(IsValid());
+  return getpriority(PRIO_PROCESS, process_);
+}
+
+}  // namespace base
diff --git a/libchrome/base/profiler/scoped_profile.cc b/libchrome/base/profiler/scoped_profile.cc
new file mode 100644
index 0000000..f06a8c6
--- /dev/null
+++ b/libchrome/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/libchrome/base/profiler/scoped_profile.h b/libchrome/base/profiler/scoped_profile.h
new file mode 100644
index 0000000..657150a
--- /dev/null
+++ b/libchrome/base/profiler/scoped_profile.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.
+
+
+#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/macros.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/libchrome/base/profiler/scoped_tracker.cc b/libchrome/base/profiler/scoped_tracker.cc
new file mode 100644
index 0000000..d15b7de
--- /dev/null
+++ b/libchrome/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/libchrome/base/profiler/scoped_tracker.h b/libchrome/base/profiler/scoped_tracker.h
new file mode 100644
index 0000000..a61de91
--- /dev/null
+++ b/libchrome/base/profiler/scoped_tracker.h
@@ -0,0 +1,77 @@
+// 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/macros.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/libchrome/base/profiler/tracked_time.cc b/libchrome/base/profiler/tracked_time.cc
new file mode 100644
index 0000000..7e0040c
--- /dev/null
+++ b/libchrome/base/profiler/tracked_time.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/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_t 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_t Duration::InMilliseconds() const {
+  return ms_;
+}
+
+//------------------------------------------------------------------------------
+
+TrackedTime::TrackedTime() : ms_(0) {}
+TrackedTime::TrackedTime(int32_t ms) : ms_(ms) {}
+TrackedTime::TrackedTime(const base::TimeTicks& time)
+    : ms_(static_cast<int32_t>((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/libchrome/base/profiler/tracked_time.h b/libchrome/base/profiler/tracked_time.h
new file mode 100644
index 0000000..b32f41b
--- /dev/null
+++ b/libchrome/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 <stdint.h>
+
+#include "base/base_export.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_t InMilliseconds() const;
+
+ private:
+  friend class TrackedTime;
+  explicit Duration(int32_t duration);
+
+  // Internal time is stored directly in milliseconds.
+  int32_t 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_t ms) { return TrackedTime(ms); }
+
+ private:
+  friend class Duration;
+  explicit TrackedTime(int32_t ms);
+
+  // Internal duration is stored directly in milliseconds.
+  uint32_t ms_;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_TRACKED_TIME_H_
diff --git a/libchrome/base/profiler/tracked_time_unittest.cc b/libchrome/base/profiler/tracked_time_unittest.cc
new file mode 100644
index 0000000..f6d35ba
--- /dev/null
+++ b/libchrome/base/profiler/tracked_time_unittest.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium 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 <stdint.h>
+
+#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_t kSomeMilliseconds = 243;  // Some example times.
+  int64_t 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/libchrome/base/rand_util.cc b/libchrome/base/rand_util.cc
new file mode 100644
index 0000000..fab6c66
--- /dev/null
+++ b/libchrome/base/rand_util.cc
@@ -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.
+
+#include "base/rand_util.h"
+
+#include <limits.h>
+#include <math.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+int RandInt(int min, int max) {
+  DCHECK_LE(min, max);
+
+  uint64_t range = static_cast<uint64_t>(max) - min + 1;
+  // |range| is at most UINT_MAX + 1, so the result of RandGenerator(range)
+  // is at most UINT_MAX.  Hence it's safe to cast it from uint64_t to int64_t.
+  int result =
+      static_cast<int>(min + static_cast<int64_t>(base::RandGenerator(range)));
+  DCHECK_GE(result, min);
+  DCHECK_LE(result, max);
+  return result;
+}
+
+double RandDouble() {
+  return BitsToOpenEndedUnitInterval(base::RandUint64());
+}
+
+double BitsToOpenEndedUnitInterval(uint64_t 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.
+
+  static_assert(std::numeric_limits<double>::radix == 2,
+                "otherwise use scalbn");
+  static const int kBits = std::numeric_limits<double>::digits;
+  uint64_t 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_t RandGenerator(uint64_t 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_t max_acceptable_value =
+      (std::numeric_limits<uint64_t>::max() / range) * range - 1;
+
+  uint64_t 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/libchrome/base/rand_util.h b/libchrome/base/rand_util.h
new file mode 100644
index 0000000..881dbd5
--- /dev/null
+++ b/libchrome/base/rand_util.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_RAND_UTIL_H_
+#define BASE_RAND_UTIL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Returns a random number in range [0, UINT64_MAX]. Thread-safe.
+BASE_EXPORT uint64_t 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_t RandGenerator(uint64_t 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_t 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/libchrome/base/rand_util_posix.cc b/libchrome/base/rand_util_posix.cc
new file mode 100644
index 0000000..6a6e05a
--- /dev/null
+++ b/libchrome/base/rand_util_posix.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/rand_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.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_t RandUint64() {
+  uint64_t 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/libchrome/base/rand_util_unittest.cc b/libchrome/base/rand_util_unittest.cc
new file mode 100644
index 0000000..4f46b80
--- /dev/null
+++ b/libchrome/base/rand_util_unittest.cc
@@ -0,0 +1,154 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+
+#include "base/logging.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, RandInt) {
+  EXPECT_EQ(base::RandInt(0, 0), 0);
+  EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
+  EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
+
+  // Check that the DCHECKS in RandInt() don't fire due to internal overflow.
+  // There was a 50% chance of that happening, so calling it 40 times means
+  // the chances of this passing by accident are tiny (9e-13).
+  for (int i = 0; i < 40; ++i)
+    base::RandInt(kIntMin, 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_t>::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_t kTopOfRange =
+      (std::numeric_limits<uint64_t>::max() / 4ULL) * 3ULL;
+  const uint64_t kExpectedAverage = kTopOfRange / 2ULL;
+  const uint64_t kAllowedVariance = kExpectedAverage / 50ULL;  // +/- 2%
+  const int kMinAttempts = 1000;
+  const int kMaxAttempts = 1000000;
+
+  double cumulative_average = 0.0;
+  int count = 0;
+  while (count < kMaxAttempts) {
+    uint64_t 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_t kAllZeros = 0ULL;
+  uint64_t kAllOnes = ~kAllZeros;
+  uint64_t found_ones = kAllZeros;
+  uint64_t found_zeros = kAllOnes;
+
+  for (size_t i = 0; i < 1000; ++i) {
+    uint64_t 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;
+
+  std::unique_ptr<uint8_t[]> buffer(new uint8_t[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/libchrome/base/run_loop.cc b/libchrome/base/run_loop.cc
new file mode 100644
index 0000000..a2322f8
--- /dev/null
+++ b/libchrome/base/run_loop.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2012 The Chromium Authors. All 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"
+#include "build/build_config.h"
+
+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) {
+}
+
+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();
+  }
+}
+
+void RunLoop::QuitWhenIdle() {
+  quit_when_idle_received_ = true;
+}
+
+base::Closure RunLoop::QuitClosure() {
+  return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
+}
+
+base::Closure RunLoop::QuitWhenIdleClosure() {
+  return base::Bind(&RunLoop::QuitWhenIdle, 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;
+
+  if (run_depth_ > 1)
+    loop_->NotifyBeginNestedLoop();
+
+  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/libchrome/base/run_loop.h b/libchrome/base/run_loop.h
new file mode 100644
index 0000000..635018f
--- /dev/null
+++ b/libchrome/base/run_loop.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.
+
+#ifndef BASE_RUN_LOOP_H_
+#define BASE_RUN_LOOP_H_
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
+
+namespace base {
+#if defined(OS_ANDROID)
+class MessagePumpForUI;
+#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();
+  ~RunLoop();
+
+  // Run the current MessageLoop. This blocks until Quit is called. Before
+  // calling Run, be sure to grab the QuitClosure in order to stop the
+  // MessageLoop asynchronously. MessageLoop::QuitWhenIdle 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() quits an earlier call to Run() immediately. QuitWhenIdle() quits an
+  // earlier call to Run() when there aren't any tasks or messages in the queue.
+  //
+  // There can be other nested RunLoops servicing the same task queue
+  // (MessageLoop); Quitting one RunLoop has no bearing on the others. Quit()
+  // and QuitWhenIdle() can be called before, during or after Run(). If called
+  // before Run(), Run() will return immediately when called. Calling Quit() or
+  // QuitWhenIdle() after the RunLoop has already finished running has no
+  // effect.
+  //
+  // WARNING: You must NEVER assume that a call to Quit() or QuitWhenIdle() 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();
+  void QuitWhenIdle();
+
+  // Convenience methods to get a closure that safely calls Quit() or
+  // QuitWhenIdle() (has no effect if the RunLoop instance is gone).
+  //
+  // Example:
+  //   RunLoop run_loop;
+  //   PostTask(run_loop.QuitClosure());
+  //   run_loop.Run();
+  base::Closure QuitClosure();
+  base::Closure QuitWhenIdleClosure();
+
+ 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_;
+
+  // 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/libchrome/base/scoped_clear_errno.h b/libchrome/base/scoped_clear_errno.h
new file mode 100644
index 0000000..585f6f7
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/scoped_clear_errno_unittest.cc b/libchrome/base/scoped_clear_errno_unittest.cc
new file mode 100644
index 0000000..8afb33e
--- /dev/null
+++ b/libchrome/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/libchrome/base/scoped_generic.h b/libchrome/base/scoped_generic.h
new file mode 100644
index 0000000..84de6b7
--- /dev/null
+++ b/libchrome/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/macros.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 {
+ 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_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedGeneric);
+};
+
+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/libchrome/base/scoped_generic_unittest.cc b/libchrome/base/scoped_generic_unittest.cc
new file mode 100644
index 0000000..5a6abfb
--- /dev/null
+++ b/libchrome/base/scoped_generic_unittest.cc
@@ -0,0 +1,172 @@
+// 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/scoped_generic.h"
+
+#include <utility>
+#include <vector>
+
+#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();
+
+  // Move constructor.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(std::move(a));
+    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();
+
+  // Move assign.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(kSecond, traits);
+    b = std::move(a);
+    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/libchrome/base/scoped_observer.h b/libchrome/base/scoped_observer.h
new file mode 100644
index 0000000..13d7ca8
--- /dev/null
+++ b/libchrome/base/scoped_observer.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_SCOPED_OBSERVER_H_
+#define BASE_SCOPED_OBSERVER_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.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 ContainsValue(sources_, source);
+  }
+
+  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/libchrome/base/security_unittest.cc b/libchrome/base/security_unittest.cc
new file mode 100644
index 0000000..af9d2bf
--- /dev/null
+++ b/libchrome/base/security_unittest.cc
@@ -0,0 +1,187 @@
+// 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 <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/free_deleter.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
+
+using std::nothrow;
+using std::numeric_limits;
+
+namespace {
+
+// 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
+
+#if defined(OS_LINUX) && defined(__x86_64__)
+// Detect runtime TCMalloc bypasses.
+bool IsTcMallocBypassed() {
+  // This should detect a TCMalloc bypass from Valgrind.
+  char* g_slice = getenv("G_SLICE");
+  if (g_slice && !strcmp(g_slice, "always-malloc"))
+    return true;
+  return false;
+}
+#endif
+
+// 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(OS_LINUX)
+#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.
+// Disabled on Linux because failing Linux Valgrind bot, and Valgrind exclusions
+// are not currently read. See http://crbug.com/582398
+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);
+  {
+    std::unique_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
+  {
+    std::unique_ptr<char[][kArraySize2]> array_pointer(
+        new (nothrow) char[kDynamicArraySize][kArraySize2]);
+    OverflowTestsSoftExpectTrue(!array_pointer);
+  }
+#endif  // !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
+}
+
+#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;
+  std::unique_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/libchrome/base/sequence_checker.h b/libchrome/base/sequence_checker.h
new file mode 100644
index 0000000..ad01828
--- /dev/null
+++ b/libchrome/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/libchrome/base/sequence_checker_impl.cc b/libchrome/base/sequence_checker_impl.cc
new file mode 100644
index 0000000..e95b8ee
--- /dev/null
+++ b/libchrome/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/libchrome/base/sequence_checker_impl.h b/libchrome/base/sequence_checker_impl.h
new file mode 100644
index 0000000..e3c5fed
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/sequence_checker_unittest.cc b/libchrome/base/sequence_checker_unittest.cc
new file mode 100644
index 0000000..196bb1c
--- /dev/null
+++ b/libchrome/base/sequence_checker_unittest.cc
@@ -0,0 +1,335 @@
+// 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/sequence_checker.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.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();
+  }
+
+ 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(
+      std::unique_ptr<SequenceCheckedObject> sequence_checked_object) {
+    other_thread()->message_loop()->task_runner()->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_;
+  std::unique_ptr<SequencedWorkerPoolOwner> pool_owner_;
+};
+
+TEST_F(SequenceCheckerTest, CallsAllowedOnSameThread) {
+  std::unique_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) {
+  std::unique_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // Verify the destructor doesn't assert when called on a different thread.
+  PostDeleteToOtherThread(std::move(sequence_checked_object));
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, DetachFromSequence) {
+  std::unique_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) {
+  std::unique_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(std::move(sequence_checked_object));
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) {
+  std::unique_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(std::move(sequence_checked_object));
+  other_thread()->Stop();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::MethodOnDifferentThreadDeathTest() {
+  std::unique_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() {
+  std::unique_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() {
+  std::unique_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(std::move(sequence_checked_object));
+  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() {
+  std::unique_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() {
+  std::unique_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();
+}
+
+#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/libchrome/base/sequenced_task_runner.cc b/libchrome/base/sequenced_task_runner.cc
new file mode 100644
index 0000000..00d4048
--- /dev/null
+++ b/libchrome/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/libchrome/base/sequenced_task_runner.h b/libchrome/base/sequenced_task_runner.h
new file mode 100644
index 0000000..6bb3f2b
--- /dev/null
+++ b/libchrome/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/libchrome/base/sequenced_task_runner_helpers.h b/libchrome/base/sequenced_task_runner_helpers.h
new file mode 100644
index 0000000..7980b46
--- /dev/null
+++ b/libchrome/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/debug/alias.h"
+#include "base/macros.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/libchrome/base/sha1.h b/libchrome/base/sha1.h
new file mode 100644
index 0000000..902e301
--- /dev/null
+++ b/libchrome/base/sha1.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_SHA1_H_
+#define BASE_SHA1_H_
+
+#include <stddef.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/libchrome/base/sha1_portable.cc b/libchrome/base/sha1_portable.cc
new file mode 100644
index 0000000..dd2ab6f
--- /dev/null
+++ b/libchrome/base/sha1_portable.cc
@@ -0,0 +1,217 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#include <string.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_t A, B, C, D, E;
+
+  uint32_t H[5];
+
+  union {
+    uint32_t W[80];
+    uint8_t M[64];
+  };
+
+  uint32_t cursor;
+  uint64_t l;
+};
+
+static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t 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_t S(uint32_t n, uint32_t X) {
+  return (X << n) | (X >> (32-n));
+}
+
+static inline uint32_t K(uint32_t 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 = (*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_t* d = reinterpret_cast<const uint8_t*>(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 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_t 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/libchrome/base/sha1_unittest.cc b/libchrome/base/sha1_unittest.cc
new file mode 100644
index 0000000..ea9cf63
--- /dev/null
+++ b/libchrome/base/sha1_unittest.cc
@@ -0,0 +1,109 @@
+// 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 <stddef.h>
+
+#include <string>
+
+#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/libchrome/base/single_thread_task_runner.h b/libchrome/base/single_thread_task_runner.h
new file mode 100644
index 0000000..6e93193
--- /dev/null
+++ b/libchrome/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/libchrome/base/stl_util.h b/libchrome/base/stl_util.h
new file mode 100644
index 0000000..12e226a
--- /dev/null
+++ b/libchrome/base/stl_util.h
@@ -0,0 +1,262 @@
+// 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);
+}
+
+// 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/libchrome/base/stl_util_unittest.cc b/libchrome/base/stl_util_unittest.cc
new file mode 100644
index 0000000..42004eb
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/OWNERS b/libchrome/base/strings/OWNERS
new file mode 100644
index 0000000..5381872
--- /dev/null
+++ b/libchrome/base/strings/OWNERS
@@ -0,0 +1,2 @@
+per-file safe_sprintf*=jln@chromium.org
+per-file safe_sprintf*=mdempsky@chromium.org
diff --git a/libchrome/base/strings/nullable_string16.cc b/libchrome/base/strings/nullable_string16.cc
new file mode 100644
index 0000000..07f81d4
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/nullable_string16.h b/libchrome/base/strings/nullable_string16.h
new file mode 100644
index 0000000..016c25c
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/nullable_string16_unittest.cc b/libchrome/base/strings/nullable_string16_unittest.cc
new file mode 100644
index 0000000..f02fdce
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/pattern.cc b/libchrome/base/strings/pattern.cc
new file mode 100644
index 0000000..af30aab
--- /dev/null
+++ b/libchrome/base/strings/pattern.cc
@@ -0,0 +1,169 @@
+// 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/strings/pattern.h"
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+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;
+  }
+};
+
+}  // namespace
+
+bool MatchPattern(const StringPiece& eval, const StringPiece& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(),
+                       pattern.data(), pattern.data() + pattern.size(),
+                       0, NextCharUTF8());
+}
+
+bool MatchPattern(const StringPiece16& eval, const StringPiece16& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(),
+                       pattern.data(), pattern.data() + pattern.size(),
+                       0, NextCharUTF16());
+}
+
+}  // namespace base
diff --git a/libchrome/base/strings/pattern.h b/libchrome/base/strings/pattern.h
new file mode 100644
index 0000000..b698207
--- /dev/null
+++ b/libchrome/base/strings/pattern.h
@@ -0,0 +1,26 @@
+// 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_STRINGS_PATTERN_H_
+#define BASE_STRINGS_PATTERN_H_
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// 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 StringPiece& string,
+                              const StringPiece& pattern);
+BASE_EXPORT bool MatchPattern(const StringPiece16& string,
+                              const StringPiece16& pattern);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_PATTERN_H_
diff --git a/libchrome/base/strings/pattern_unittest.cc b/libchrome/base/strings/pattern_unittest.cc
new file mode 100644
index 0000000..9e82b3c
--- /dev/null
+++ b/libchrome/base/strings/pattern_unittest.cc
@@ -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.
+
+#include "base/strings/pattern.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+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")));
+}
+
+}  // namespace base
diff --git a/libchrome/base/strings/safe_sprintf.cc b/libchrome/base/strings/safe_sprintf.cc
new file mode 100644
index 0000000..a51c778
--- /dev/null
+++ b/libchrome/base/strings/safe_sprintf.cc
@@ -0,0 +1,686 @@
+// 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 <errno.h>
+#include <string.h>
+
+#include <limits>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#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 static_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) {
+// MSVS2013's standard library 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(__clang__) && defined(OS_WIN))
+    static_assert(kSSizeMaxConst ==
+                      static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
+                  "kSSizeMaxConst should be 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/libchrome/base/strings/safe_sprintf.h b/libchrome/base/strings/safe_sprintf.h
new file mode 100644
index 0000000..65524a5
--- /dev/null
+++ b/libchrome/base/strings/safe_sprintf.h
@@ -0,0 +1,246 @@
+// 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"
+
+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/libchrome/base/strings/safe_sprintf_unittest.cc b/libchrome/base/strings/safe_sprintf_unittest.cc
new file mode 100644
index 0000000..1a21728
--- /dev/null
+++ b/libchrome/base/strings/safe_sprintf_unittest.cc
@@ -0,0 +1,763 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <limits>
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.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";
+  std::unique_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.
+  std::unique_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 (std::unique_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/libchrome/base/strings/string16.cc b/libchrome/base/strings/string16.cc
new file mode 100644
index 0000000..f4c8cf7
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/string16.h b/libchrome/base/strings/string16.h
new file mode 100644
index 0000000..30f4e3e
--- /dev/null
+++ b/libchrome/base/strings/string16.h
@@ -0,0 +1,206 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <functional>
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.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)
+
+#include <wchar.h>  // for mbstate_t
+
+namespace base {
+
+typedef uint16_t 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().
+  static_assert(sizeof(int_type) > sizeof(char_type),
+                "int must be larger than 16 bits wide");
+
+  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>;
+
+// Specialize std::hash for base::string16. Although the style guide forbids
+// this in general, it is necessary for consistency with WCHAR_T_IS_UTF16
+// platforms, where base::string16 is a type alias for std::wstring.
+namespace std {
+template <>
+struct hash<base::string16> {
+  std::size_t operator()(const base::string16& s) const {
+    std::size_t result = 0;
+    for (base::char16 c : s)
+      result = (result * 131) + c;
+    return result;
+  }
+};
+}  // namespace std
+
+#endif  // WCHAR_T_IS_UTF32
+
+#endif  // BASE_STRINGS_STRING16_H_
diff --git a/libchrome/base/strings/string16_unittest.cc b/libchrome/base/strings/string16_unittest.cc
new file mode 100644
index 0000000..0d2ca80
--- /dev/null
+++ b/libchrome/base/strings/string16_unittest.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 <sstream>
+#include <unordered_set>
+
+#include "base/strings/string16.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// 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());
+  }
+}
+
+TEST(String16Test, Hash) {
+  string16 str1 = ASCIIToUTF16("hello");
+  string16 str2 = ASCIIToUTF16("world");
+
+  std::unordered_set<string16> set;
+
+  set.insert(str1);
+  EXPECT_EQ(1u, set.count(str1));
+  EXPECT_EQ(0u, set.count(str2));
+}
+
+}  // namespace base
diff --git a/libchrome/base/strings/string_number_conversions.cc b/libchrome/base/strings/string_number_conversions.cc
new file mode 100644
index 0000000..09aeb44
--- /dev/null
+++ b/libchrome/base/strings/string_number_conversions.cc
@@ -0,0 +1,489 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/numerics/safe_math.h"
+#include "base/scoped_clear_errno.h"
+#include "base/scoped_clear_errno.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT>
+struct IntToStringT {
+  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 size_t kOutputBufSize =
+        3 * sizeof(INT) + std::numeric_limits<INT>::is_signed;
+
+    // Create the string in a temporary buffer, write it back to front, and
+    // then return the substr of what we ended up using.
+    using CHR = typename STR::value_type;
+    CHR outbuf[kOutputBufSize];
+
+    // The ValueOrDie call below can never fail, because UnsignedAbs is valid
+    // for all valid inputs.
+    auto res = CheckedNumeric<INT>(value).UnsignedAbs().ValueOrDie();
+
+    CHR* end = outbuf + kOutputBufSize;
+    CHR* i = end;
+    do {
+      --i;
+      DCHECK(i != outbuf);
+      *i = static_cast<CHR>((res % 10) + '0');
+      res /= 10;
+    } while (res != 0);
+    if (IsValueNegative(value)) {
+      --i;
+      DCHECK(i != outbuf);
+      *i = static_cast<CHR>('-');
+    }
+    return STR(i, 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_t* digit) {
+    if (c >= '0' && c < '0' + BASE) {
+      *digit = static_cast<uint8_t>(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_t* 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_t* digit) {
+  return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
+}
+
+// There is an IsUnicodeWhitespace 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) {
+        *output = 0;
+        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_t 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_t 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_t increment, value_type* output) {
+      *output += increment;
+    }
+  };
+
+  class Negative : public Base<Negative> {
+   public:
+    static bool CheckBounds(value_type* output, uint8_t 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_t 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_t, 16> {};
+
+template <typename ITERATOR>
+class BaseHexIteratorRangeToInt64Traits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, int64_t, 16> {};
+
+template <typename ITERATOR>
+class BaseHexIteratorRangeToUInt64Traits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64_t, 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_t>* 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_t msb = 0;  // most significant 4 bits
+    uint8_t 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>::IntToString(value);
+}
+
+string16 IntToString16(int value) {
+  return IntToStringT<string16, int>::IntToString(value);
+}
+
+std::string UintToString(unsigned int value) {
+  return IntToStringT<std::string, unsigned int>::IntToString(value);
+}
+
+string16 UintToString16(unsigned int value) {
+  return IntToStringT<string16, unsigned int>::IntToString(value);
+}
+
+std::string Int64ToString(int64_t value) {
+  return IntToStringT<std::string, int64_t>::IntToString(value);
+}
+
+string16 Int64ToString16(int64_t value) {
+  return IntToStringT<string16, int64_t>::IntToString(value);
+}
+
+std::string Uint64ToString(uint64_t value) {
+  return IntToStringT<std::string, uint64_t>::IntToString(value);
+}
+
+string16 Uint64ToString16(uint64_t value) {
+  return IntToStringT<string16, uint64_t>::IntToString(value);
+}
+
+std::string SizeTToString(size_t value) {
+  return IntToStringT<std::string, size_t>::IntToString(value);
+}
+
+string16 SizeTToString16(size_t value) {
+  return IntToStringT<string16, size_t>::IntToString(value);
+}
+
+std::string DoubleToString(double value) {
+  auto ret = std::to_string(value);
+  // If this returned an integer, don't do anything.
+  if (ret.find('.') == std::string::npos) {
+    return ret;
+  }
+  // Otherwise, it has an annoying tendency to leave trailing zeros.
+  size_t len = ret.size();
+  while (len >= 2 && ret[len - 1] == '0' && ret[len - 2] != '.') {
+    --len;
+  }
+  ret.erase(len);
+  return ret;
+}
+
+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_t* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToInt64(const StringPiece16& input, int64_t* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece& input, uint64_t* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece16& input, uint64_t* 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) {
+  char* endptr = nullptr;
+  *output = strtod(input.c_str(), &endptr);
+
+  // Cases to return false:
+  //  - 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 !input.empty() &&
+         input.c_str() + input.length() == endptr &&
+         !isspace(input[0]) &&
+         *output != std::numeric_limits<double>::infinity() &&
+         *output != -std::numeric_limits<double>::infinity();
+}
+
+// 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_t* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
+      input.begin(), input.end(), output);
+}
+
+bool HexStringToInt64(const StringPiece& input, int64_t* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
+    input.begin(), input.end(), output);
+}
+
+bool HexStringToUInt64(const StringPiece& input, uint64_t* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
+      input.begin(), input.end(), output);
+}
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8_t>* output) {
+  return HexStringToBytesT(input, output);
+}
+
+}  // namespace base
diff --git a/libchrome/base/strings/string_number_conversions.h b/libchrome/base/strings/string_number_conversions.h
new file mode 100644
index 0000000..a95544e
--- /dev/null
+++ b/libchrome/base/strings/string_number_conversions.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_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.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.
+//
+// DO NOT use these functions in any UI unless it's NOT localized on purpose.
+// Instead, use base::MessageFormatter for a complex message with numbers
+// (integer, float, double) embedded or base::Format{Number,Double,Percent} to
+// just format a single number/percent. Note that some languages use native
+// digits instead of ASCII digits while others use a group separator or decimal
+// point different from ',' and '.'. Using these functions in the UI would lead
+// numbers to be formatted in a non-native way.
+// ----------------------------------------------------------------------------
+
+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_t value);
+BASE_EXPORT string16 Int64ToString16(int64_t value);
+
+BASE_EXPORT std::string Uint64ToString(uint64_t value);
+BASE_EXPORT string16 Uint64ToString16(uint64_t value);
+
+BASE_EXPORT std::string SizeTToString(size_t value);
+BASE_EXPORT string16 SizeTToString16(size_t value);
+
+// Deprecated: prefer std::to_string(double) instead.
+// 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.
+// WARNING: Will write to |output| even when returning false.
+//          Read the comments above carefully.
+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_t* output);
+BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64_t* output);
+
+BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64_t* output);
+BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64_t* output);
+
+BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
+BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
+
+// Deprecated: prefer std::stod() instead.
+// 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-finite 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.
+// WARNING: Will write to |output| even when returning false.
+//          Read the comments here and above StringToInt() carefully.
+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_t* 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_t* 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_t* 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_t>* output);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
diff --git a/libchrome/base/strings/string_number_conversions_unittest.cc b/libchrome/base/strings/string_number_conversions_unittest.cc
new file mode 100644
index 0000000..91191e0
--- /dev/null
+++ b/libchrome/base/strings/string_number_conversions_unittest.cc
@@ -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.
+
+#include "base/strings/string_number_conversions.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <cmath>
+#include <limits>
+
+#include "base/bit_cast.h"
+#include "base/format_macros.h"
+#include "base/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_t> int64_tests[] = {
+      {0, "0", "0"},
+      {-1, "-1", "18446744073709551615"},
+      {
+          std::numeric_limits<int64_t>::max(), "9223372036854775807",
+          "9223372036854775807",
+      },
+      {std::numeric_limits<int64_t>::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_t>* 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_t input;
+    std::string output;
+  } cases[] = {
+      {0, "0"},
+      {42, "42"},
+      {INT_MAX, "2147483647"},
+      {std::numeric_limits<uint64_t>::max(), "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 = cases[i].output ^ 1;  // Ensure StringToInt wrote something.
+    EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = cases[i].output ^ 1;  // Ensure StringToInt wrote something.
+    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 =
+        cases[i].output ^ 1;  // Ensure StringToUint wrote something.
+    EXPECT_EQ(cases[i].success, StringToUint(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = cases[i].output ^ 1;  // Ensure StringToUint wrote something.
+    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_t 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", std::numeric_limits<int64_t>::max(), true},
+      {"-9223372036854775808", std::numeric_limits<int64_t>::min(), 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", std::numeric_limits<int64_t>::min(), false},
+      {"-99999999999999999999", std::numeric_limits<int64_t>::min(), false},
+      {"9223372036854775808", std::numeric_limits<int64_t>::max(), false},
+      {"99999999999999999999", std::numeric_limits<int64_t>::max(), false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int64_t 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_t 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_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", UINT64_C(2147483648), true},
+      {"99999999999", UINT64_C(99999999999), true},
+      {"9223372036854775807", std::numeric_limits<int64_t>::max(), 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", std::numeric_limits<uint64_t>::max(), false},
+      {"18446744073709551615", std::numeric_limits<uint64_t>::max(), true},
+      {"18446744073709551616", std::numeric_limits<uint64_t>::max(), false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64_t 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_t 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_t 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_t 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", std::numeric_limits<uint32_t>::max(), true},
+      {"0XDeadBeef", 0xdeadbeef, true},
+      {"0x7fffffffffffffff", std::numeric_limits<uint32_t>::max(),
+       false},  // Overflow test.
+      {"-0x8000000000000000", 0, false},
+      {"0x8000000000000000", std::numeric_limits<uint32_t>::max(),
+       false},  // Overflow test.
+      {"-0x8000000000000001", 0, false},
+      {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+       false},  // Overflow test.
+      {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+       false},  // Overflow test.
+      {"0x0000000000000000", 0, true},
+      {"0000000000000000", 0, true},
+      {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+       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_t 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_t output;
+  EXPECT_FALSE(HexStringToUInt(input_string, &output));
+  EXPECT_EQ(0xc0ffeeU, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt64) {
+  static const struct {
+    std::string input;
+    int64_t 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", std::numeric_limits<int64_t>::max(), true},
+      {"-0x8000000000000000", std::numeric_limits<int64_t>::min(), true},
+      {"0x8000000000000000", std::numeric_limits<int64_t>::max(),
+       false},  // Overflow test.
+      {"-0x8000000000000001", std::numeric_limits<int64_t>::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) {
+    int64_t 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_t output;
+  EXPECT_FALSE(HexStringToInt64(input_string, &output));
+  EXPECT_EQ(0xc0ffee, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToUInt64) {
+  static const struct {
+    std::string input;
+    uint64_t 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", std::numeric_limits<int64_t>::max(), true},
+      {"-0x8000000000000000", 0, false},
+      {"0x8000000000000000", UINT64_C(0x8000000000000000), true},
+      {"-0x8000000000000001", 0, false},
+      {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true},
+      {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true},
+      {"0x0000000000000000", 0, true},
+      {"0000000000000000", 0, true},
+      {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(),
+       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_t 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_t 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_t> output;
+    std::vector<uint8_t> 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_t>(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", std::numeric_limits<double>::infinity(),
+                               false},
+    {"-9e99999999999999999999", -std::numeric_limits<double>::infinity(),
+                                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))
+        << "for input=" << cases[i].input << "got output=" << 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.0"},
+    {1.25, "1.25"},
+    {1.33518e+012, "1335180000000.0"},
+    {1.33489e+012, "1334890000000.0"},
+    {1.33505e+012, "1335050000000.0"},
+    {1.33545e+009, "1335450000.0"},
+    {1.33503e+009, "1335030000.0"},
+  };
+
+  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.0", 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.0", 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/libchrome/base/strings/string_piece.cc b/libchrome/base/strings/string_piece.cc
new file mode 100644
index 0000000..c26bb36
--- /dev/null
+++ b/libchrome/base/strings/string_piece.cc
@@ -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.cc with modifications
+
+#include "base/strings/string_piece.h"
+
+#include <limits.h>
+
+#include <algorithm>
+#include <ostream>
+
+#include "base/logging.h"
+
+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);
+}
+
+#if DCHECK_IS_ON()
+void AssertIteratorsInOrder(std::string::const_iterator begin,
+                            std::string::const_iterator end) {
+  DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
+}
+void AssertIteratorsInOrder(string16::const_iterator begin,
+                            string16::const_iterator end) {
+  DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
+}
+#endif
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/strings/string_piece.h b/libchrome/base/strings/string_piece.h
new file mode 100644
index 0000000..eaec14d
--- /dev/null
+++ b/libchrome/base/strings/string_piece.h
@@ -0,0 +1,464 @@
+// Copyright (c) 2012 The Chromium 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/logging.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);
+
+#if DCHECK_IS_ON()
+// Asserts that begin <= end to catch some errors with iterator usage.
+BASE_EXPORT void AssertIteratorsInOrder(std::string::const_iterator begin,
+                                        std::string::const_iterator end);
+BASE_EXPORT void AssertIteratorsInOrder(string16::const_iterator begin,
+                                        string16::const_iterator end);
+#endif
+
+}  // 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) {
+#if DCHECK_IS_ON()
+    // This assertion is done out-of-line to avoid bringing in logging.h and
+    // instantiating logging macros for every instantiation.
+    internal::AssertIteratorsInOrder(begin, end);
+#endif
+    length_ = static_cast<size_t>(std::distance(begin, end));
+
+    // The length test before assignment is to avoid dereferencing an iterator
+    // that may point to the end() of a string.
+    ptr_ = length_ > 0 ? &*begin : nullptr;
+  }
+
+  // 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]; }
+  value_type front() const { return ptr_[0]; }
+  value_type back() const { return ptr_[length_ - 1]; }
+
+  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);
+
+// 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/strings/string16.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;
+
+struct StringPieceHash {
+  std::size_t operator()(const StringPiece& sp) const {
+    HASH_STRING_PIECE(StringPiece, sp);
+  }
+};
+struct StringPiece16Hash {
+  std::size_t operator()(const StringPiece16& sp16) const {
+    HASH_STRING_PIECE(StringPiece16, sp16);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_PIECE_H_
diff --git a/libchrome/base/strings/string_piece_unittest.cc b/libchrome/base/strings/string_piece_unittest.cc
new file mode 100644
index 0000000..f05aa15
--- /dev/null
+++ b/libchrome/base/strings/string_piece_unittest.cc
@@ -0,0 +1,691 @@
+// Copyright (c) 2012 The Chromium Authors. 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 <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/libchrome/base/strings/string_split.cc b/libchrome/base/strings/string_split.cc
new file mode 100644
index 0000000..6c949b9
--- /dev/null
+++ b/libchrome/base/strings/string_split.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/strings/string_split.h"
+
+#include <stddef.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 AppendStringKeyValue(StringPiece input,
+                          char delimiter,
+                          StringPairs* result) {
+  // Always append a new item regardless of success (it might be empty). The
+  // below code will copy the strings directly into the result pair.
+  result->resize(result->size() + 1);
+  auto& result_pair = result->back();
+
+  // Find the delimiter.
+  size_t end_key_pos = input.find_first_of(delimiter);
+  if (end_key_pos == std::string::npos) {
+    DVLOG(1) << "cannot find delimiter in: " << input;
+    return false;    // No delimiter.
+  }
+  input.substr(0, end_key_pos).CopyToString(&result_pair.first);
+
+  // Find the value string.
+  StringPiece remains = input.substr(end_key_pos, input.size() - end_key_pos);
+  size_t begin_value_pos = remains.find_first_not_of(delimiter);
+  if (begin_value_pos == StringPiece::npos) {
+    DVLOG(1) << "cannot parse value from input: " << input;
+    return false;   // No value.
+  }
+  remains.substr(begin_value_pos, remains.size() - begin_value_pos)
+      .CopyToString(&result_pair.second);
+
+  return true;
+}
+
+template <typename Str, typename OutputStringType>
+void SplitStringUsingSubstrT(BasicStringPiece<Str> input,
+                             BasicStringPiece<Str> delimiter,
+                             WhitespaceHandling whitespace,
+                             SplitResult result_type,
+                             std::vector<OutputStringType>* result) {
+  using Piece = BasicStringPiece<Str>;
+  using size_type = typename Piece::size_type;
+
+  result->clear();
+  for (size_type begin_index = 0, end_index = 0; end_index != Piece::npos;
+       begin_index = end_index + delimiter.size()) {
+    end_index = input.find(delimiter, begin_index);
+    Piece term = end_index == Piece::npos
+                     ? input.substr(begin_index)
+                     : input.substr(begin_index, end_index - begin_index);
+
+    if (whitespace == TRIM_WHITESPACE)
+      term = TrimString(term, WhitespaceForType<Str>(), TRIM_ALL);
+
+    if (result_type == SPLIT_WANT_ALL || !term.empty())
+      result->push_back(PieceToOutputType<Str, OutputStringType>(term));
+  }
+}
+
+}  // 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);
+}
+
+bool SplitStringIntoKeyValuePairs(StringPiece input,
+                                  char key_value_delimiter,
+                                  char key_value_pair_delimiter,
+                                  StringPairs* key_value_pairs) {
+  key_value_pairs->clear();
+
+  std::vector<StringPiece> pairs = SplitStringPiece(
+      input, std::string(1, key_value_pair_delimiter),
+      TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  key_value_pairs->reserve(pairs.size());
+
+  bool success = true;
+  for (const StringPiece& pair : pairs) {
+    if (!AppendStringKeyValue(pair, key_value_delimiter, key_value_pairs)) {
+      // Don't return here, to allow for pairs without associated
+      // value or key; just record that the split failed.
+      success = false;
+    }
+  }
+  return success;
+}
+
+void SplitStringUsingSubstr(StringPiece16 input,
+                            StringPiece16 delimiter,
+                            std::vector<string16>* result) {
+  SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
+                          result);
+}
+
+void SplitStringUsingSubstr(StringPiece input,
+                            StringPiece delimiter,
+                            std::vector<std::string>* result) {
+  SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
+                          result);
+}
+
+std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+    StringPiece16 input,
+    StringPiece16 delimiter,
+    WhitespaceHandling whitespace,
+    SplitResult result_type) {
+  std::vector<StringPiece16> result;
+  SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
+  return result;
+}
+
+std::vector<StringPiece> SplitStringPieceUsingSubstr(
+    StringPiece input,
+    StringPiece delimiter,
+    WhitespaceHandling whitespace,
+    SplitResult result_type) {
+  std::vector<StringPiece> result;
+  SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
+  return result;
+}
+
+}  // namespace base
diff --git a/libchrome/base/strings/string_split.h b/libchrome/base/strings/string_split.h
new file mode 100644
index 0000000..ec9f246
--- /dev/null
+++ b/libchrome/base/strings/string_split.h
@@ -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.
+
+#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(StringPiece input,
+                                              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(StringPiece16 input,
+                                        StringPiece16 delimiter,
+                                        std::vector<string16>* result);
+BASE_EXPORT void SplitStringUsingSubstr(StringPiece input,
+                                        StringPiece delimiter,
+                                        std::vector<std::string>* result);
+
+// Like SplitStringUsingSubstr 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 newline-separated tokens in an input string:
+//
+//   for (const auto& cur :
+//        base::SplitStringUsingSubstr(input, "\r\n",
+//                                     base::KEEP_WHITESPACE,
+//                                     base::SPLIT_WANT_NONEMPTY)) {
+//     ...
+BASE_EXPORT std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+    StringPiece16 input,
+    StringPiece16 delimiter,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr(
+    StringPiece input,
+    StringPiece delimiter,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_SPLIT_H_
diff --git a/libchrome/base/strings/string_split_unittest.cc b/libchrome/base/strings/string_split_unittest.cc
new file mode 100644
index 0000000..657a2db
--- /dev/null
+++ b/libchrome/base/strings/string_split_unittest.cc
@@ -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/strings/string_split.h"
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/strings/string_util.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 {
+
+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(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(SplitStringPieceUsingSubstrTest, StringWithNoDelimiter) {
+  std::vector<base::StringPiece> results =
+      SplitStringPieceUsingSubstr("alongwordwithnodelimiter", "DELIMITER",
+                                  base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, LeadingDelimitersSkipped) {
+  std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+      "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree", "DELIMITER",
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(6u, results.size());
+  EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, ConsecutiveDelimitersSkipped) {
+  std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+      "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
+      "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, TrailingDelimitersSkipped) {
+  std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+      "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
+      "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(results,
+              ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, KeepWhitespace) {
+  std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+      "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER",
+      base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(4u, results.size());
+  EXPECT_THAT(results, ElementsAre("un ", "deux\t", "trois\n", "quatre"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, TrimWhitespace) {
+  std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+      "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER",
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(4u, results.size());
+  EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "quatre"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, SplitWantAll) {
+  std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+      "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER",
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(5u, results.size());
+  EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "", ""));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, SplitWantNonEmpty) {
+  std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+      "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER",
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(3u, results.size());
+  EXPECT_THAT(results, ElementsAre("un", "deux", "trois"));
+}
+
+TEST(StringSplitTest, StringSplitKeepWhitespace) {
+  std::vector<std::string> r;
+
+  r = SplitString("   ", "*", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], "   ");
+
+  r = SplitString("\t  \ta\t ", "\t", base::KEEP_WHITESPACE,
+                  base::SPLIT_WANT_ALL);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], "");
+  EXPECT_EQ(r[1], "  ");
+  EXPECT_EQ(r[2], "a");
+  EXPECT_EQ(r[3], " ");
+
+  r = SplitString("\ta\t\nb\tcc", "\n", base::KEEP_WHITESPACE,
+                  base::SPLIT_WANT_ALL);
+  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 = base::SplitString(
+        data[i].input, kWhitespaceASCII, base::KEEP_WHITESPACE,
+        base::SPLIT_WANT_NONEMPTY);
+    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/libchrome/base/strings/string_tokenizer.h b/libchrome/base/strings/string_tokenizer.h
new file mode 100644
index 0000000..8defbac
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/string_tokenizer_unittest.cc b/libchrome/base/strings/string_tokenizer_unittest.cc
new file mode 100644
index 0000000..d391845
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/string_util.cc b/libchrome/base/strings/string_util.cc
new file mode 100644
index 0000000..cb668ed
--- /dev/null
+++ b/libchrome/base/strings/string_util.cc
@@ -0,0 +1,997 @@
+// 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/singleton.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"
+
+namespace base {
+
+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, char16> {
+    static inline uint32_t value() { return 0xFF80FF80U; }
+};
+template<> struct NonASCIIMask<4, char> {
+    static inline uint32_t value() { return 0x80808080U; }
+};
+template<> struct NonASCIIMask<8, 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
+
+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;
+}
+
+namespace {
+
+template<typename StringType>
+StringType ToLowerASCIIImpl(BasicStringPiece<StringType> str) {
+  StringType ret;
+  ret.reserve(str.size());
+  for (size_t i = 0; i < str.size(); i++)
+    ret.push_back(ToLowerASCII(str[i]));
+  return ret;
+}
+
+template<typename StringType>
+StringType ToUpperASCIIImpl(BasicStringPiece<StringType> str) {
+  StringType ret;
+  ret.reserve(str.size());
+  for (size_t i = 0; i < str.size(); i++)
+    ret.push_back(ToUpperASCII(str[i]));
+  return ret;
+}
+
+}  // namespace
+
+std::string ToLowerASCII(StringPiece str) {
+  return ToLowerASCIIImpl<std::string>(str);
+}
+
+string16 ToLowerASCII(StringPiece16 str) {
+  return ToLowerASCIIImpl<string16>(str);
+}
+
+std::string ToUpperASCII(StringPiece str) {
+  return ToUpperASCIIImpl<std::string>(str);
+}
+
+string16 ToUpperASCII(StringPiece16 str) {
+  return ToUpperASCIIImpl<string16>(str);
+}
+
+template<class StringType>
+int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
+                                 BasicStringPiece<StringType> b) {
+  // Find the first characters that aren't equal and compare them.  If the end
+  // of one of the strings is found before a nonequal character, the lengths
+  // of the strings are compared.
+  size_t i = 0;
+  while (i < a.length() && i < b.length()) {
+    typename StringType::value_type lower_a = ToLowerASCII(a[i]);
+    typename StringType::value_type lower_b = ToLowerASCII(b[i]);
+    if (lower_a < lower_b)
+      return -1;
+    if (lower_a > lower_b)
+      return 1;
+    i++;
+  }
+
+  // End of one string hit before finding a different character. Expect the
+  // common case to be "strings equal" at this point so check that first.
+  if (a.length() == b.length())
+    return 0;
+
+  if (a.length() < b.length())
+    return -1;
+  return 1;
+}
+
+int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+  return CompareCaseInsensitiveASCIIT<std::string>(a, b);
+}
+
+int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+  return CompareCaseInsensitiveASCIIT<string16>(a, b);
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+  if (a.length() != b.length())
+    return false;
+  return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0;
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+  if (a.length() != b.length())
+    return false;
+  return CompareCaseInsensitiveASCIIT<string16>(a, b) == 0;
+}
+
+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 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 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 StringPiece16& remove_chars,
+                 string16* output) {
+  return ReplaceChars(input, remove_chars.as_string(), string16(), output);
+}
+
+bool RemoveChars(const std::string& input,
+                 const 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,
+                StringPiece16 trim_chars,
+                string16* output) {
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+bool TrimString(const std::string& input,
+                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 StringPiece16& trim_chars,
+                         TrimPositions positions) {
+  return TrimStringPieceT(input, trim_chars, positions);
+}
+
+StringPiece TrimString(StringPiece input,
+                       const 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_t>(std::numeric_limits<int32_t>::max()));
+  // Note: This cast is necessary because CBU8_NEXT uses int32_ts.
+  int32_t truncation_length = static_cast<int32_t>(byte_size);
+  int32_t 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_t 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);
+}
+
+StringPiece16 TrimWhitespace(StringPiece16 input,
+                             TrimPositions positions) {
+  return TrimStringPieceT(input, StringPiece16(kWhitespaceUTF16), positions);
+}
+
+TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                  TrimPositions positions,
+                                  std::string* output) {
+  return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output);
+}
+
+StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
+  return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
+}
+
+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 (IsUnicodeWhitespace(*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_t src_len = static_cast<int32_t>(str.length());
+  int32_t char_index = 0;
+
+  while (char_index < src_len) {
+    int32_t code_point;
+    CBU8_NEXT(src, char_index, src_len, code_point);
+    if (!IsValidCharacter(code_point))
+      return false;
+  }
+  return true;
+}
+
+// Implementation note: Normally this function will be called with a hardcoded
+// constant for the lowercase_ascii parameter. Constructing a StringPiece from
+// a C constant requires running strlen, so the result will be two passes
+// through the buffers, one to file the length of lowercase_ascii, and one to
+// compare each letter.
+//
+// This function could have taken a const char* to avoid this and only do one
+// pass through the string. But the strlen is faster than the case-insensitive
+// compares and lets us early-exit in the case that the strings are different
+// lengths (will often be the case for non-matches). So whether one approach or
+// the other will be faster depends on the case.
+//
+// The hardcoded strings are typically very short so it doesn't matter, and the
+// string piece gives additional flexibility for the caller (doesn't have to be
+// null terminated) so we choose the StringPiece route.
+template<typename Str>
+static inline bool DoLowerCaseEqualsASCII(BasicStringPiece<Str> str,
+                                          StringPiece lowercase_ascii) {
+  if (str.size() != lowercase_ascii.size())
+    return false;
+  for (size_t i = 0; i < str.size(); i++) {
+    if (ToLowerASCII(str[i]) != lowercase_ascii[i])
+      return false;
+  }
+  return true;
+}
+
+bool LowerCaseEqualsASCII(StringPiece str, StringPiece lowercase_ascii) {
+  return DoLowerCaseEqualsASCII<std::string>(str, lowercase_ascii);
+}
+
+bool LowerCaseEqualsASCII(StringPiece16 str, StringPiece lowercase_ascii) {
+  return DoLowerCaseEqualsASCII<string16>(str, lowercase_ascii);
+}
+
+bool EqualsASCII(StringPiece16 str, StringPiece ascii) {
+  if (str.length() != ascii.length())
+    return false;
+  return std::equal(ascii.begin(), ascii.end(), str.begin());
+}
+
+template<typename Str>
+bool StartsWithT(BasicStringPiece<Str> str,
+                 BasicStringPiece<Str> search_for,
+                 CompareCase case_sensitivity) {
+  if (search_for.size() > str.size())
+    return false;
+
+  BasicStringPiece<Str> source = str.substr(0, search_for.size());
+
+  switch (case_sensitivity) {
+    case CompareCase::SENSITIVE:
+      return source == search_for;
+
+    case CompareCase::INSENSITIVE_ASCII:
+      return std::equal(
+          search_for.begin(), search_for.end(),
+          source.begin(),
+          CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool StartsWith(StringPiece str,
+                StringPiece search_for,
+                CompareCase case_sensitivity) {
+  return StartsWithT<std::string>(str, search_for, case_sensitivity);
+}
+
+bool StartsWith(StringPiece16 str,
+                StringPiece16 search_for,
+                CompareCase case_sensitivity) {
+  return StartsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+template <typename Str>
+bool EndsWithT(BasicStringPiece<Str> str,
+               BasicStringPiece<Str> search_for,
+               CompareCase case_sensitivity) {
+  if (search_for.size() > str.size())
+    return false;
+
+  BasicStringPiece<Str> source = str.substr(str.size() - search_for.size(),
+                                            search_for.size());
+
+  switch (case_sensitivity) {
+    case CompareCase::SENSITIVE:
+      return source == search_for;
+
+    case CompareCase::INSENSITIVE_ASCII:
+      return std::equal(
+          source.begin(), source.end(),
+          search_for.begin(),
+          CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool EndsWith(StringPiece str,
+              StringPiece search_for,
+              CompareCase case_sensitivity) {
+  return EndsWithT<std::string>(str, search_for, case_sensitivity);
+}
+
+bool EndsWith(StringPiece16 str,
+              StringPiece16 search_for,
+              CompareCase case_sensitivity) {
+  return EndsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+char HexDigitToInt(wchar_t 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;
+}
+
+bool IsUnicodeWhitespace(wchar_t c) {
+  // kWhitespaceWide is a NULL-terminated string
+  for (const wchar_t* cur = kWhitespaceWide; *cur; ++cur) {
+    if (*cur == c)
+      return true;
+  }
+  return false;
+}
+
+static const char* const kByteStringsUnlocalized[] = {
+  " B",
+  " kB",
+  " MB",
+  " GB",
+  " TB",
+  " PB"
+};
+
+string16 FormatBytesUnlocalized(int64_t 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 ASCIIToUTF16(buf);
+}
+
+// Runs in O(n) time in the length of |str|.
+template<class StringType>
+void DoReplaceSubstringsAfterOffset(StringType* str,
+                                    size_t offset,
+                                    BasicStringPiece<StringType> find_this,
+                                    BasicStringPiece<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.data(), offset, find_this.size());
+  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.data(), replace_with.size());
+    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.data(), replace_with.size());
+      offset = str->find(find_this.data(), offset + replace_length,
+                         find_this.size());
+    } 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.data(), replace_with.size());
+        write_offset += replace_length;
+      }
+      size_t read_offset = offset + find_length;
+      offset = std::min(
+          str->find(find_this.data(), read_offset, find_this.size()),
+          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.data(), offset + find_length,
+                       find_this.size());
+  } 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.data(), current_match - 1,
+                                  find_this.size())) {
+    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.data(), replace_with.size());
+    if (current_match == first_match)
+      return;
+    prev_match = current_match;
+  }
+}
+
+void ReplaceFirstSubstringAfterOffset(string16* str,
+                                      size_t start_offset,
+                                      StringPiece16 find_this,
+                                      StringPiece16 replace_with) {
+  DoReplaceSubstringsAfterOffset<string16>(
+      str, start_offset, find_this, replace_with, false);  // Replace first.
+}
+
+void ReplaceFirstSubstringAfterOffset(std::string* str,
+                                      size_t start_offset,
+                                      StringPiece find_this,
+                                      StringPiece replace_with) {
+  DoReplaceSubstringsAfterOffset<std::string>(
+      str, start_offset, find_this, replace_with, false);  // Replace first.
+}
+
+void ReplaceSubstringsAfterOffset(string16* str,
+                                  size_t start_offset,
+                                  StringPiece16 find_this,
+                                  StringPiece16 replace_with) {
+  DoReplaceSubstringsAfterOffset<string16>(
+      str, start_offset, find_this, replace_with, true);  // Replace all.
+}
+
+void ReplaceSubstringsAfterOffset(std::string* str,
+                                  size_t start_offset,
+                                  StringPiece find_this,
+                                  StringPiece replace_with) {
+  DoReplaceSubstringsAfterOffset<std::string>(
+      str, start_offset, find_this, replace_with, true);  // Replace all.
+}
+
+template <class string_type>
+inline typename string_type::value_type* WriteIntoT(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]);
+}
+
+char* WriteInto(std::string* str, size_t length_with_null) {
+  return WriteIntoT(str, length_with_null);
+}
+
+char16* WriteInto(string16* str, size_t length_with_null) {
+  return WriteIntoT(str, length_with_null);
+}
+
+template<typename STR>
+static STR JoinStringT(const std::vector<STR>& parts,
+                       BasicStringPiece<STR> sep) {
+  if (parts.empty())
+    return STR();
+
+  STR result(parts[0]);
+  auto iter = parts.begin();
+  ++iter;
+
+  for (; iter != parts.end(); ++iter) {
+    sep.AppendToString(&result);
+    result += *iter;
+  }
+
+  return result;
+}
+
+std::string JoinString(const std::vector<std::string>& parts,
+                       StringPiece separator) {
+  return JoinStringT(parts, separator);
+}
+
+string16 JoinString(const std::vector<string16>& parts,
+                    StringPiece16 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();
+  DCHECK_LT(substitutions, 10U);
+
+  size_t sub_length = 0;
+  for (const auto& cur : subst)
+    sub_length += cur.length();
+
+  OutStringType formatted;
+  formatted.reserve(format_string.length() + sub_length);
+
+  std::vector<ReplacementOffset> r_offsets;
+  for (auto i = format_string.begin(); i != format_string.end(); ++i) {
+    if ('$' == *i) {
+      if (i + 1 != format_string.end()) {
+        ++i;
+        if ('$' == *i) {
+          while (i != format_string.end() && '$' == *i) {
+            formatted.push_back('$');
+            ++i;
+          }
+          --i;
+        } else {
+          if (*i < '1' || *i > '9') {
+            DLOG(ERROR) << "Invalid placeholder: $" << *i;
+            continue;
+          }
+          uintptr_t index = *i - '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 (const auto& cur : r_offsets)
+      offsets->push_back(cur.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 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;
+}
+
+// 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 strlcpy(char* dst, const char* src, size_t dst_size) {
+  return lcpyT<char>(dst, src, dst_size);
+}
+size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+  return lcpyT<wchar_t>(dst, src, dst_size);
+}
+
+}  // namespace base
diff --git a/libchrome/base/strings/string_util.h b/libchrome/base/strings/string_util.h
new file mode 100644
index 0000000..0ee077c
--- /dev/null
+++ b/libchrome/base/strings/string_util.h
@@ -0,0 +1,475 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"  // For implicit conversions.
+#include "build/build_config.h"
+
+#if defined(ANDROID)
+// On Android, bionic's stdio.h defines an snprintf macro when being built with
+// clang. Undefine it here so it won't collide with base::snprintf().
+#undef snprintf
+#endif  // defined(ANDROID)
+
+namespace base {
+
+// C standard-library functions that aren't cross-platform are provided as
+// "base::...", and their prototypes are listed below. These functions are
+// then implemented as inline calls to the platform-specific equivalents in the
+// platform-specific headers.
+
+// 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,
+                    _Printf_format_string_ const char* format,
+                    ...) PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer,
+                    size_t size,
+                    _Printf_format_string_ 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.
+inline char ToLowerASCII(char c) {
+  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+inline char16 ToLowerASCII(char16 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.
+inline char ToUpperASCII(char c) {
+  return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+inline char16 ToUpperASCII(char16 c) {
+  return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+
+// Converts the given string to it's ASCII-lowercase equivalent.
+BASE_EXPORT std::string ToLowerASCII(StringPiece str);
+BASE_EXPORT string16 ToLowerASCII(StringPiece16 str);
+
+// Converts the given string to it's ASCII-uppercase equivalent.
+BASE_EXPORT std::string ToUpperASCII(StringPiece str);
+BASE_EXPORT string16 ToUpperASCII(StringPiece16 str);
+
+// Functor for case-insensitive ASCII comparisons for STL algorithms like
+// std::search.
+//
+// Note that a full Unicode version of this functor is not possible to write
+// because case mappings might change the number of characters, depend on
+// context (combining accents), and require handling UTF-16. If you need
+// proper Unicode support, use base::i18n::ToLower/FoldCase and then just
+// use a normal operator== on the result.
+template<typename Char> struct CaseInsensitiveCompareASCII {
+ public:
+  bool operator()(Char x, Char y) const {
+    return ToLowerASCII(x) == ToLowerASCII(y);
+  }
+};
+
+// Like strcasecmp for case-insensitive ASCII characters only. Returns:
+//   -1  (a < b)
+//    0  (a == b)
+//    1  (a > b)
+// (unlike strcasecmp which can return values greater or less than 1/-1). For
+// full Unicode support, use base::i18n::ToLower or base::i18h::FoldCase
+// and then just call the normal string operators on the result.
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
+// Equality for ASCII case-insensitive comparisons. For full Unicode support,
+// use base::i18n::ToLower or base::i18h::FoldCase and then compare with either
+// == or !=.
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
+// 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 StringPiece16& remove_chars,
+                             string16* output);
+BASE_EXPORT bool RemoveChars(const std::string& input,
+                             const 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 StringPiece16& replace_chars,
+                              const string16& replace_with,
+                              string16* output);
+BASE_EXPORT bool ReplaceChars(const std::string& input,
+                              const 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,
+                            StringPiece16 trim_chars,
+                            string16* output);
+BASE_EXPORT bool TrimString(const std::string& input,
+                            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 StringPiece16& trim_chars,
+                                     TrimPositions positions);
+BASE_EXPORT StringPiece TrimString(StringPiece input,
+                                   const 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.
+//
+// The StringPiece versions return a substring referencing the input buffer.
+// The ASCII versions look only for ASCII whitespace.
+//
+// The std::string versions return where whitespace was found.
+// NOTE: Safe to use the same variable for both input and output.
+BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
+                                         TrimPositions positions,
+                                         string16* output);
+BASE_EXPORT StringPiece16 TrimWhitespace(StringPiece16 input,
+                                         TrimPositions positions);
+BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                              TrimPositions positions,
+                                              std::string* output);
+BASE_EXPORT StringPiece TrimWhitespaceASCII(StringPiece input,
+                                            TrimPositions positions);
+
+// 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
+
+// Compare the lower-case form of the given string against the given
+// previously-lower-cased ASCII string (typically a constant).
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece str,
+                                      StringPiece lowecase_ascii);
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece16 str,
+                                      StringPiece lowecase_ascii);
+
+// Performs a case-sensitive string compare of the given 16-bit string against
+// the given 8-bit ASCII string (typically a constant). The behavior is
+// undefined if the |ascii| string is not ASCII.
+BASE_EXPORT bool EqualsASCII(StringPiece16 str, StringPiece ascii);
+
+// Indicates case sensitivity of comparisons. Only ASCII case insensitivity
+// is supported. Full Unicode case-insensitive conversions would need to go in
+// base/i18n so it can use ICU.
+//
+// If you need to do Unicode-aware case-insensitive StartsWith/EndsWith, it's
+// best to call base::i18n::ToLower() or base::i18n::FoldCase() (see
+// base/i18n/case_conversion.h for usage advice) on the arguments, and then use
+// the results to a case-sensitive comparison.
+enum class CompareCase {
+  SENSITIVE,
+  INSENSITIVE_ASCII,
+};
+
+BASE_EXPORT bool StartsWith(StringPiece str,
+                            StringPiece search_for,
+                            CompareCase case_sensitivity);
+BASE_EXPORT bool StartsWith(StringPiece16 str,
+                            StringPiece16 search_for,
+                            CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece str,
+                          StringPiece search_for,
+                          CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece16 str,
+                          StringPiece16 search_for,
+                          CompareCase case_sensitivity);
+
+// 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 IsAsciiUpper(Char c) {
+  return c >= 'A' && c <= 'Z';
+}
+template <typename Char>
+inline bool IsAsciiLower(Char c) {
+  return 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');
+}
+
+// Returns the integer corresponding to the given hex character. For example:
+//    '4' -> 4
+//    'a' -> 10
+//    'B' -> 11
+// Assumes the input is a valid hex character. DCHECKs in debug builds if not.
+BASE_EXPORT char HexDigitToInt(wchar_t c);
+
+// Returns true if it's a Unicode whitespace character.
+BASE_EXPORT bool IsUnicodeWhitespace(wchar_t c);
+
+// 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 string16 FormatBytesUnlocalized(int64_t 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,
+    StringPiece16 find_this,
+    StringPiece16 replace_with);
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+    std::string* str,
+    size_t start_offset,
+    StringPiece find_this,
+    StringPiece 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(
+    string16* str,
+    size_t start_offset,
+    StringPiece16 find_this,
+    StringPiece16 replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+    std::string* str,
+    size_t start_offset,
+    StringPiece find_this,
+    StringPiece 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).
+BASE_EXPORT char* WriteInto(std::string* str, size_t length_with_null);
+BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null);
+#ifndef OS_WIN
+BASE_EXPORT wchar_t* WriteInto(std::wstring* str, size_t length_with_null);
+#endif
+
+// Does the opposite of SplitString().
+BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
+                                   StringPiece separator);
+BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
+                                StringPiece16 separator);
+
+// Replace $1-$2-$3..$9 in the format string with values from |subst|.
+// 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 string16 ReplaceStringPlaceholders(
+    const string16& format_string,
+    const std::vector<string16>& subst,
+    std::vector<size_t>* offsets);
+
+BASE_EXPORT std::string ReplaceStringPlaceholders(
+    const 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 string16 ReplaceStringPlaceholders(const string16& format_string,
+                                               const string16& a,
+                                               size_t* offset);
+
+}  // 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
+
+#endif  // BASE_STRINGS_STRING_UTIL_H_
diff --git a/libchrome/base/strings/string_util_constants.cc b/libchrome/base/strings/string_util_constants.cc
new file mode 100644
index 0000000..aba1b12
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/string_util_posix.h b/libchrome/base/strings/string_util_posix.h
new file mode 100644
index 0000000..8299118
--- /dev/null
+++ b/libchrome/base/strings/string_util_posix.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_STRINGS_STRING_UTIL_POSIX_H_
+#define BASE_STRINGS_STRING_UTIL_POSIX_H_
+
+#include <stdarg.h>
+#include <stddef.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 vsnprintf(char* buffer, size_t size,
+                     const char* format, va_list arguments) {
+  return ::vsnprintf(buffer, size, format, arguments);
+}
+
+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/libchrome/base/strings/string_util_unittest.cc b/libchrome/base/strings/string_util_unittest.cc
new file mode 100644
index 0000000..df2226e
--- /dev/null
+++ b/libchrome/base/strings/string_util_unittest.cc
@@ -0,0 +1,1130 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/macros.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,
+              TrimWhitespaceASCII(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, ToLowerASCII) {
+  EXPECT_EQ('c', ToLowerASCII('C'));
+  EXPECT_EQ('c', ToLowerASCII('c'));
+  EXPECT_EQ('2', ToLowerASCII('2'));
+
+  EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('C')));
+  EXPECT_EQ(static_cast<char16>('c'), ToLowerASCII(static_cast<char16>('c')));
+  EXPECT_EQ(static_cast<char16>('2'), ToLowerASCII(static_cast<char16>('2')));
+
+  EXPECT_EQ("cc2", ToLowerASCII("Cc2"));
+  EXPECT_EQ(ASCIIToUTF16("cc2"), ToLowerASCII(ASCIIToUTF16("Cc2")));
+}
+
+TEST(StringUtilTest, ToUpperASCII) {
+  EXPECT_EQ('C', ToUpperASCII('C'));
+  EXPECT_EQ('C', ToUpperASCII('c'));
+  EXPECT_EQ('2', ToUpperASCII('2'));
+
+  EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('C')));
+  EXPECT_EQ(static_cast<char16>('C'), ToUpperASCII(static_cast<char16>('c')));
+  EXPECT_EQ(static_cast<char16>('2'), ToUpperASCII(static_cast<char16>('2')));
+
+  EXPECT_EQ("CC2", ToUpperASCII("Cc2"));
+  EXPECT_EQ(ASCIIToUTF16("CC2"), ToUpperASCII(ASCIIToUTF16("Cc2")));
+}
+
+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_t 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(StringUtilTest, JoinString) {
+  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(StringUtilTest, JoinString16) {
+  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(StartsWith("javascript:url", "javascript",
+                         base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith("JavaScript:url", "javascript",
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith("javascript:url", "javascript",
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith("JavaScript:url", "javascript",
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith("java", "javascript", base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith("java", "javascript",
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(std::string(), "javascript",
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(std::string(), "javascript",
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith("java", std::string(),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith("java", std::string(), base::CompareCase::SENSITIVE));
+
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("JavaScript:url"),
+                          ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("JavaScript:url"),
+                         ASCIIToUTF16("javascript"),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"), ASCIIToUTF16("javascript"),
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+                          base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"),
+                          base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+                         base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(),
+                         base::CompareCase::SENSITIVE));
+}
+
+TEST(StringUtilTest, EndsWith) {
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"),
+                        base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_TRUE(
+      EndsWith(string16(), string16(), base::CompareCase::INSENSITIVE_ASCII));
+  EXPECT_TRUE(EndsWith(string16(), string16(), base::CompareCase::SENSITIVE));
+}
+
+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, nullptr);
+
+  EXPECT_EQ(ASCIIToUTF16("9aa,8bb,7cc,d,e,f,9ag,8bh,7ci"), formatted);
+}
+
+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, nullptr);
+
+  EXPECT_EQ(ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii"), formatted);
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersOneDigit) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("1a"));
+  string16 formatted =
+      ReplaceStringPlaceholders(ASCIIToUTF16(" $16 "), subst, nullptr);
+  EXPECT_EQ(ASCIIToUTF16(" 1a6 "), formatted);
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersInvalidPlaceholder) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("1a"));
+  string16 formatted =
+      ReplaceStringPlaceholders(ASCIIToUTF16("+$-+$A+$1+"), subst, nullptr);
+  EXPECT_EQ(ASCIIToUTF16("+++1a+"), formatted);
+}
+
+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, nullptr);
+
+  EXPECT_EQ("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii", formatted);
+}
+
+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, nullptr),
+            "$1 $$2 $$$3");
+}
+
+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));
+}
+
+TEST(StringUtilTest, CompareCaseInsensitiveASCII) {
+  EXPECT_EQ(0, CompareCaseInsensitiveASCII("", ""));
+  EXPECT_EQ(0, CompareCaseInsensitiveASCII("Asdf", "aSDf"));
+
+  // Differing lengths.
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("Asdf", "aSDfA"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("AsdfA", "aSDf"));
+
+  // Differing values.
+  EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb"));
+  EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA"));
+}
+
+TEST(StringUtilTest, EqualsCaseInsensitiveASCII) {
+  EXPECT_TRUE(EqualsCaseInsensitiveASCII("", ""));
+  EXPECT_TRUE(EqualsCaseInsensitiveASCII("Asdf", "aSDF"));
+  EXPECT_FALSE(EqualsCaseInsensitiveASCII("bsdf", "aSDF"));
+  EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", "aSDFz"));
+}
+
+TEST(StringUtilTest, IsUnicodeWhitespace) {
+  // NOT unicode white space.
+  EXPECT_FALSE(IsUnicodeWhitespace(L'\0'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'A'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'0'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'.'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L';'));
+  EXPECT_FALSE(IsUnicodeWhitespace(L'\x4100'));
+
+  // Actual unicode whitespace.
+  EXPECT_TRUE(IsUnicodeWhitespace(L' '));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\xa0'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\x3000'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\t'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\r'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\v'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\f'));
+  EXPECT_TRUE(IsUnicodeWhitespace(L'\n'));
+}
+
+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/libchrome/base/strings/string_util_win.h b/libchrome/base/strings/string_util_win.h
new file mode 100644
index 0000000..7f260bf
--- /dev/null
+++ b/libchrome/base/strings/string_util_win.h
@@ -0,0 +1,44 @@
+// 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 <stddef.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 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/libchrome/base/strings/stringize_macros.h b/libchrome/base/strings/stringize_macros.h
new file mode 100644
index 0000000..d4e2707
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/stringize_macros_unittest.cc b/libchrome/base/strings/stringize_macros_unittest.cc
new file mode 100644
index 0000000..d7f9e56
--- /dev/null
+++ b/libchrome/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/libchrome/base/strings/stringprintf.cc b/libchrome/base/strings/stringprintf.cc
new file mode 100644
index 0000000..415845d
--- /dev/null
+++ b/libchrome/base/strings/stringprintf.cc
@@ -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.
+
+#include "base/strings/stringprintf.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/scoped_clear_errno.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.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/libchrome/base/strings/stringprintf.h b/libchrome/base/strings/stringprintf.h
new file mode 100644
index 0000000..7a75d89
--- /dev/null
+++ b/libchrome/base/strings/stringprintf.h
@@ -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.
+
+#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"
+#include "build/build_config.h"
+
+namespace base {
+
+// Return a C++ string given printf-like input.
+BASE_EXPORT std::string StringPrintf(_Printf_format_string_ const char* format,
+                                     ...)
+    PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+#if defined(OS_WIN)
+BASE_EXPORT std::wstring StringPrintf(
+    _Printf_format_string_ 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,
+    _Printf_format_string_ const char* format,
+    ...) PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT const std::wstring& SStringPrintf(
+    std::wstring* dst,
+    _Printf_format_string_ const wchar_t* format,
+    ...) WPRINTF_FORMAT(2, 3);
+#endif
+
+// Append result to a supplied string.
+BASE_EXPORT void StringAppendF(std::string* dst,
+                               _Printf_format_string_ const char* format,
+                               ...) PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT void StringAppendF(std::wstring* dst,
+                               _Printf_format_string_ 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/libchrome/base/strings/stringprintf_unittest.cc b/libchrome/base/strings/stringprintf_unittest.cc
new file mode 100644
index 0000000..e2d3a90
--- /dev/null
+++ b/libchrome/base/strings/stringprintf_unittest.cc
@@ -0,0 +1,182 @@
+// 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 <stddef.h>
+
+#include "base/macros.h"
+#include "build/build_config.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());
+}
+
+#if defined(OS_WIN)
+// vswprintf in Visual Studio 2013 fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled. In Visual Studio 2015 the bad character
+// is passed through.
+TEST(StringPrintfTest, Invalid) {
+  wchar_t invalid[2];
+  invalid[0] = 0xffff;
+  invalid[1] = 0;
+
+  std::wstring out;
+  SStringPrintf(&out, L"%ls", invalid);
+#if _MSC_VER >= 1900
+  EXPECT_STREQ(invalid, out.c_str());
+#else
+  EXPECT_STREQ(L"", out.c_str());
+#endif
+}
+#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/libchrome/base/strings/sys_string_conversions.h b/libchrome/base/strings/sys_string_conversions.h
new file mode 100644
index 0000000..b41a228
--- /dev/null
+++ b/libchrome/base/strings/sys_string_conversions.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_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 <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.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_t code_page);
+BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide,
+                                           uint32_t 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/libchrome/base/strings/sys_string_conversions_mac.mm b/libchrome/base/strings/sys_string_conversions_mac.mm
new file mode 100644
index 0000000..32fe89c
--- /dev/null
+++ b/libchrome/base/strings/sys_string_conversions_mac.mm
@@ -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/strings/sys_string_conversions.h"
+
+#import <Foundation/Foundation.h>
+#include <stddef.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/libchrome/base/strings/sys_string_conversions_posix.cc b/libchrome/base/strings/sys_string_conversions_posix.cc
new file mode 100644
index 0000000..a8dcfd0
--- /dev/null
+++ b/libchrome/base/strings/sys_string_conversions_posix.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/strings/sys_string_conversions.h"
+
+#include <stddef.h>
+#include <wchar.h>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.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/libchrome/base/strings/sys_string_conversions_unittest.cc b/libchrome/base/strings/sys_string_conversions_unittest.cc
new file mode 100644
index 0000000..f5ffaec
--- /dev/null
+++ b/libchrome/base/strings/sys_string_conversions_unittest.cc
@@ -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.
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/macros.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 "build/build_config.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/libchrome/base/strings/utf_string_conversion_utils.cc b/libchrome/base/strings/utf_string_conversion_utils.cc
new file mode 100644
index 0000000..22058a5
--- /dev/null
+++ b/libchrome/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_t src_len,
+                          int32_t* char_index,
+                          uint32_t* 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_t code_point;
+  CBU8_NEXT(src, *char_index, src_len, code_point);
+  *code_point_out = static_cast<uint32_t>(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_t src_len,
+                          int32_t* char_index,
+                          uint32_t* 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_t /*src_len*/,
+                          int32_t* char_index,
+                          uint32_t* 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_t 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_t 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/libchrome/base/strings/utf_string_conversion_utils.h b/libchrome/base/strings/utf_string_conversion_utils.h
new file mode 100644
index 0000000..c716404
--- /dev/null
+++ b/libchrome/base/strings/utf_string_conversion_utils.h
@@ -0,0 +1,99 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+inline bool IsValidCodepoint(uint32_t 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_t 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_t src_len,
+                                      int32_t* char_index,
+                                      uint32_t* 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_t src_len,
+                                      int32_t* char_index,
+                                      uint32_t* 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_t src_len,
+                                      int32_t* char_index,
+                                      uint32_t* 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.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t 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_t 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_t 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/libchrome/base/strings/utf_string_conversions.cc b/libchrome/base/strings/utf_string_conversions.cc
new file mode 100644
index 0000000..6b17eac
--- /dev/null
+++ b/libchrome/base/strings/utf_string_conversions.cc
@@ -0,0 +1,231 @@
+// 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 <stdint.h>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "build/build_config.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_t src_len32 = static_cast<int32_t>(src_len);
+  for (int32_t i = 0; i < src_len32; i++) {
+    uint32_t 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(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(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(StringPiece16 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(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(StringPiece16 utf16) {
+  if (IsStringASCII(utf16))
+    return std::string(utf16.data(), utf16.data() + utf16.length());
+
+  std::string ret;
+  PrepareForUTF8Output(utf16.data(), utf16.length(), &ret);
+  ConvertUnicode(utf16.data(), utf16.length(), &ret);
+  return ret;
+}
+
+#endif
+
+string16 ASCIIToUTF16(StringPiece ascii) {
+  DCHECK(IsStringASCII(ascii)) << ascii;
+  return string16(ascii.begin(), ascii.end());
+}
+
+std::string UTF16ToASCII(StringPiece16 utf16) {
+  DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
+  return std::string(utf16.begin(), utf16.end());
+}
+
+}  // namespace base
diff --git a/libchrome/base/strings/utf_string_conversions.h b/libchrome/base/strings/utf_string_conversions.h
new file mode 100644
index 0000000..2995f4c
--- /dev/null
+++ b/libchrome/base/strings/utf_string_conversions.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_STRINGS_UTF_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+
+#include <stddef.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(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(StringPiece utf8);
+BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
+                             std::string* output);
+BASE_EXPORT std::string UTF16ToUTF8(StringPiece16 utf16);
+
+// This converts an ASCII string, typically a hardcoded constant, to a UTF16
+// string.
+BASE_EXPORT string16 ASCIIToUTF16(StringPiece ascii);
+
+// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
+// beforehand.
+BASE_EXPORT std::string UTF16ToASCII(StringPiece16 utf16);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
diff --git a/libchrome/base/strings/utf_string_conversions_unittest.cc b/libchrome/base/strings/utf_string_conversions_unittest.cc
new file mode 100644
index 0000000..8107713
--- /dev/null
+++ b/libchrome/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 <stddef.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.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 (const auto& test : convert_cases) {
+    std::string converted;
+    EXPECT_EQ(test.success,
+              WideToUTF8(test.utf16, wcslen(test.utf16), &converted));
+    std::string expected(test.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 (const auto& test : convert_cases) {
+    std::string converted;
+    EXPECT_EQ(test.success,
+              WideToUTF8(test.utf32, wcslen(test.utf32), &converted));
+    std::string expected(test.utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+TEST(UTFStringConversionsTest, ConvertMultiString) {
+  static char16 multi16[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
+  };
+  static char multi[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
+  };
+  string16 multistring16;
+  memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
+                   sizeof(multi16));
+  EXPECT_EQ(arraysize(multi16) - 1, multistring16.length());
+  std::string expected;
+  memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
+  EXPECT_EQ(arraysize(multi) - 1, expected.length());
+  const std::string& converted = UTF16ToUTF8(multistring16);
+  EXPECT_EQ(arraysize(multi) - 1, converted.length());
+  EXPECT_EQ(expected, converted);
+}
+
+}  // namespace base
diff --git a/libchrome/base/sync_socket.h b/libchrome/base/sync_socket.h
new file mode 100644
index 0000000..fcf4155
--- /dev/null
+++ b/libchrome/base/sync_socket.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_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 <stddef.h>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <sys/types.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.
+  virtual 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/libchrome/base/sync_socket_posix.cc b/libchrome/base/sync_socket_posix.cc
new file mode 100644
index 0000000..995c8e9
--- /dev/null
+++ b/libchrome/base/sync_socket_posix.cc
@@ -0,0 +1,248 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.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"
+#include "build/build_config.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 int flags = fcntl(handle_, F_GETFL);
+  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/libchrome/base/sync_socket_unittest.cc b/libchrome/base/sync_socket_unittest.cc
new file mode 100644
index 0000000..97a1aec
--- /dev/null
+++ b/libchrome/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/macros.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;
+  static_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/libchrome/base/synchronization/cancellation_flag.cc b/libchrome/base/synchronization/cancellation_flag.cc
new file mode 100644
index 0000000..ca5c0a8
--- /dev/null
+++ b/libchrome/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/libchrome/base/synchronization/cancellation_flag.h b/libchrome/base/synchronization/cancellation_flag.h
new file mode 100644
index 0000000..f2f83f4
--- /dev/null
+++ b/libchrome/base/synchronization/cancellation_flag.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_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+#define BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/macros.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/libchrome/base/synchronization/cancellation_flag_unittest.cc b/libchrome/base/synchronization/cancellation_flag_unittest.cc
new file mode 100644
index 0000000..13c74bc
--- /dev/null
+++ b/libchrome/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/libchrome/base/synchronization/condition_variable.h b/libchrome/base/synchronization/condition_variable.h
new file mode 100644
index 0000000..ebf90d2
--- /dev/null
+++ b/libchrome/base/synchronization/condition_variable.h
@@ -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.
+
+// 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 "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+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)
+  CONDITION_VARIABLE cv_;
+  SRWLOCK* const srwlock_;
+#elif defined(OS_POSIX)
+  pthread_cond_t condition_;
+  pthread_mutex_t* user_mutex_;
+#endif
+
+#if DCHECK_IS_ON() && (defined(OS_WIN) || defined(OS_POSIX))
+  base::Lock* const user_lock_;  // Needed to adjust shadow lock state on wait.
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
diff --git a/libchrome/base/synchronization/condition_variable_posix.cc b/libchrome/base/synchronization/condition_variable_posix.cc
new file mode 100644
index 0000000..d86fd18
--- /dev/null
+++ b/libchrome/base/synchronization/condition_variable_posix.cc
@@ -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.
+
+#include "base/synchronization/condition_variable.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+    : user_mutex_(user_lock->lock_.native_handle())
+#if DCHECK_IS_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() {
+#if defined(OS_MACOSX)
+  // This hack is necessary to avoid a fatal pthreads subsystem bug in the
+  // Darwin kernel. http://crbug.com/517681.
+  {
+    base::Lock lock;
+    base::AutoLock l(lock);
+    struct timespec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = 1;
+    pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
+                                       &ts);
+  }
+#endif
+
+  int rv = pthread_cond_destroy(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Wait() {
+  base::ThreadRestrictions::AssertWaitAllowed();
+#if DCHECK_IS_ON()
+  user_lock_->CheckHeldAndUnmark();
+#endif
+  int rv = pthread_cond_wait(&condition_, user_mutex_);
+  DCHECK_EQ(0, rv);
+#if DCHECK_IS_ON()
+  user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  int64_t 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 DCHECK_IS_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 DCHECK_IS_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/libchrome/base/synchronization/condition_variable_unittest.cc b/libchrome/base/synchronization/condition_variable_unittest.cc
new file mode 100644
index 0000000..d60b2b8
--- /dev/null
+++ b/libchrome/base/synchronization/condition_variable_unittest.cc
@@ -0,0 +1,768 @@
+// Copyright (c) 2012 The Chromium 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 "base/synchronization/condition_variable.h"
+
+#include <time.h>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.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 "build/build_config.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_;
+  std::unique_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/libchrome/base/synchronization/lock.cc b/libchrome/base/synchronization/lock.cc
new file mode 100644
index 0000000..03297ad
--- /dev/null
+++ b/libchrome/base/synchronization/lock.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.
+
+// 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.
+
+#include "base/synchronization/lock.h"
+
+#if DCHECK_IS_ON()
+
+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  // DCHECK_IS_ON()
diff --git a/libchrome/base/synchronization/lock.h b/libchrome/base/synchronization/lock.h
new file mode 100644
index 0000000..fbf6cef
--- /dev/null
+++ b/libchrome/base/synchronization/lock.h
@@ -0,0 +1,136 @@
+// 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/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.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 !DCHECK_IS_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: We do not permit recursive locks and 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  // DCHECK_IS_ON()
+
+#if defined(OS_POSIX) || defined(OS_WIN)
+  // Both Windows and POSIX implementations of ConditionVariable need to be
+  // able to see our lock and tweak our debugging counters, as they release and
+  // acquire locks inside of their condition variable APIs.
+  friend class ConditionVariable;
+#endif
+
+ private:
+#if DCHECK_IS_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  // DCHECK_IS_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/libchrome/base/synchronization/lock_impl.h b/libchrome/base/synchronization/lock_impl.h
new file mode 100644
index 0000000..cbaabc7
--- /dev/null
+++ b/libchrome/base/synchronization/lock_impl.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_SYNCHRONIZATION_LOCK_IMPL_H_
+#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+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)
+  using NativeHandle = SRWLOCK;
+#elif defined(OS_POSIX)
+  using NativeHandle =  pthread_mutex_t;
+#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/libchrome/base/synchronization/lock_impl_posix.cc b/libchrome/base/synchronization/lock_impl_posix.cc
new file mode 100644
index 0000000..5619ada
--- /dev/null
+++ b/libchrome/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/libchrome/base/synchronization/lock_unittest.cc b/libchrome/base/synchronization/lock_unittest.cc
new file mode 100644
index 0000000..27f335e
--- /dev/null
+++ b/libchrome/base/synchronization/lock_unittest.cc
@@ -0,0 +1,215 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/macros.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/libchrome/base/synchronization/read_write_lock.h b/libchrome/base/synchronization/read_write_lock.h
new file mode 100644
index 0000000..4c59b7b
--- /dev/null
+++ b/libchrome/base/synchronization/read_write_lock.h
@@ -0,0 +1,105 @@
+// Copyright 2016 The Chromium Authors. All 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_READ_WRITE_LOCK_H_
+#define BASE_SYNCHRONIZATION_READ_WRITE_LOCK_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if defined(OS_NACL)
+#include "base/synchronization/lock.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#else
+#  error No reader-writer lock defined for this platform.
+#endif
+
+namespace base {
+namespace subtle {
+
+// An OS-independent wrapper around reader-writer locks. There's no magic here.
+//
+// You are strongly encouraged to use base::Lock instead of this, unless you
+// can demonstrate contention and show that this would lead to an improvement.
+// This lock does not make any guarantees of fairness, which can lead to writer
+// starvation under certain access patterns. You should carefully consider your
+// writer access patterns before using this lock.
+class BASE_EXPORT ReadWriteLock {
+ public:
+  ReadWriteLock();
+  ~ReadWriteLock();
+
+  // Reader lock functions.
+  void ReadAcquire();
+  void ReadRelease();
+
+  // Writer lock functions.
+  void WriteAcquire();
+  void WriteRelease();
+
+ private:
+#if defined(OS_WIN)
+  using NativeHandle = SRWLOCK;
+#elif defined(OS_NACL)
+  using NativeHandle = Lock;
+#elif defined(OS_POSIX)
+  using NativeHandle = pthread_rwlock_t;
+#endif
+
+  NativeHandle native_handle_;
+
+#if defined(OS_NACL)
+  // Even though NaCl has a pthread_rwlock implementation, the build rules don't
+  // make it universally available. So instead, implement a slower and trivial
+  // reader-writer lock using a regular mutex.
+  // TODO(amistry): Remove this and use the posix implementation when it's
+  // available in all build configurations.
+  uint32_t readers_ = 0;
+  // base::Lock does checking to ensure the lock is acquired and released on the
+  // same thread. This is not the case for this lock, so use pthread mutexes
+  // directly here.
+  pthread_mutex_t writer_lock_ = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ReadWriteLock);
+};
+
+class AutoReadLock {
+ public:
+  explicit AutoReadLock(ReadWriteLock& lock) : lock_(lock) {
+    lock_.ReadAcquire();
+  }
+  ~AutoReadLock() {
+    lock_.ReadRelease();
+  }
+
+ private:
+  ReadWriteLock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoReadLock);
+};
+
+class AutoWriteLock {
+ public:
+  explicit AutoWriteLock(ReadWriteLock& lock) : lock_(lock) {
+    lock_.WriteAcquire();
+  }
+  ~AutoWriteLock() {
+    lock_.WriteRelease();
+  }
+
+ private:
+  ReadWriteLock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoWriteLock);
+};
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_READ_WRITE_LOCK_H_
diff --git a/libchrome/base/synchronization/read_write_lock_posix.cc b/libchrome/base/synchronization/read_write_lock_posix.cc
new file mode 100644
index 0000000..e5de091
--- /dev/null
+++ b/libchrome/base/synchronization/read_write_lock_posix.cc
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Authors. All 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/read_write_lock.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace subtle {
+
+ReadWriteLock::ReadWriteLock() : native_handle_(PTHREAD_RWLOCK_INITIALIZER) {}
+
+ReadWriteLock::~ReadWriteLock() {
+  int result = pthread_rwlock_destroy(&native_handle_);
+  DCHECK_EQ(result, 0) << ". " << strerror(result);
+}
+
+void ReadWriteLock::ReadAcquire() {
+  int result = pthread_rwlock_rdlock(&native_handle_);
+  DCHECK_EQ(result, 0) << ". " << strerror(result);
+}
+
+void ReadWriteLock::ReadRelease() {
+  int result = pthread_rwlock_unlock(&native_handle_);
+  DCHECK_EQ(result, 0) << ". " << strerror(result);
+}
+
+void ReadWriteLock::WriteAcquire() {
+  int result = pthread_rwlock_wrlock(&native_handle_);
+  DCHECK_EQ(result, 0) << ". " << strerror(result);
+}
+
+void ReadWriteLock::WriteRelease() {
+  int result = pthread_rwlock_unlock(&native_handle_);
+  DCHECK_EQ(result, 0) << ". " << strerror(result);
+}
+
+}  // namespace subtle
+}  // namespace base
diff --git a/libchrome/base/synchronization/spin_wait.h b/libchrome/base/synchronization/spin_wait.h
new file mode 100644
index 0000000..9b147cd
--- /dev/null
+++ b/libchrome/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/libchrome/base/synchronization/waitable_event.h b/libchrome/base/synchronization/waitable_event.h
new file mode 100644
index 0000000..3863e98
--- /dev/null
+++ b/libchrome/base/synchronization/waitable_event.h
@@ -0,0 +1,196 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "build/build_config.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:
+  // Indicates whether a WaitableEvent should automatically reset the event
+  // state after a single waiting thread has been released or remain signaled
+  // until Reset() is manually invoked.
+  enum class ResetPolicy { MANUAL, AUTOMATIC };
+
+  // Indicates whether a new WaitableEvent should start in a signaled state or
+  // not.
+  enum class InitialState { SIGNALED, NOT_SIGNALED };
+
+  // Constructs a WaitableEvent with policy and initial state as detailed in
+  // the above enums.
+  WaitableEvent(ResetPolicy reset_policy, InitialState initial_state);
+
+#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(ResetPolicy reset_policy, InitialState initial_state);
+
+    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/libchrome/base/synchronization/waitable_event_posix.cc b/libchrome/base/synchronization/waitable_event_posix.cc
new file mode 100644
index 0000000..b32c882
--- /dev/null
+++ b/libchrome/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 <stddef.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.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(ResetPolicy reset_policy,
+                             InitialState initial_state)
+    : kernel_(new WaitableEventKernel(reset_policy, initial_state)) {}
+
+WaitableEvent::~WaitableEvent() = default;
+
+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(
+    ResetPolicy reset_policy,
+    InitialState initial_state)
+    : manual_reset_(reset_policy == ResetPolicy::MANUAL),
+      signaled_(initial_state == InitialState::SIGNALED) {}
+
+WaitableEvent::WaitableEventKernel::~WaitableEventKernel() = default;
+
+// -----------------------------------------------------------------------------
+// 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/libchrome/base/synchronization/waitable_event_unittest.cc b/libchrome/base/synchronization/waitable_event_unittest.cc
new file mode 100644
index 0000000..ac5c9f1
--- /dev/null
+++ b/libchrome/base/synchronization/waitable_event_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/synchronization/waitable_event.h"
+
+#include <stddef.h>
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(WaitableEventTest, ManualBasics) {
+  WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL,
+                      WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                      WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                              WaitableEvent::InitialState::NOT_SIGNALED);
+  }
+
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                        WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                              WaitableEvent::InitialState::NOT_SIGNALED);
+  }
+
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                        WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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/libchrome/base/synchronization/waitable_event_watcher.h b/libchrome/base/synchronization/waitable_event_watcher.h
new file mode 100644
index 0000000..eb51eff
--- /dev/null
+++ b/libchrome/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/libchrome/base/synchronization/waitable_event_watcher_posix.cc b/libchrome/base/synchronization/waitable_event_watcher_posix.cc
new file mode 100644
index 0000000..7cf8688
--- /dev/null
+++ b/libchrome/base/synchronization/waitable_event_watcher_posix.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/synchronization/waitable_event_watcher.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/macros.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, base::RetainedRef(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/libchrome/base/sys_byteorder.h b/libchrome/base/sys_byteorder.h
new file mode 100644
index 0000000..8d9066c
--- /dev/null
+++ b/libchrome/base/sys_byteorder.h
@@ -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.
+
+// 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 <stdint.h>
+
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness.
+inline uint16_t ByteSwap(uint16_t x) {
+#if defined(COMPILER_MSVC)
+  return _byteswap_ushort(x);
+#else
+  return __builtin_bswap16(x);
+#endif
+}
+
+inline uint32_t ByteSwap(uint32_t x) {
+#if defined(COMPILER_MSVC)
+  return _byteswap_ulong(x);
+#else
+  return __builtin_bswap32(x);
+#endif
+}
+
+inline uint64_t ByteSwap(uint64_t x) {
+#if defined(COMPILER_MSVC)
+  return _byteswap_uint64(x);
+#else
+  return __builtin_bswap64(x);
+#endif
+}
+
+// Converts the bytes in |x| from host order (endianness) to little endian, and
+// returns the result.
+inline uint16_t ByteSwapToLE16(uint16_t x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint32_t ByteSwapToLE32(uint32_t x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint64_t ByteSwapToLE64(uint64_t 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_t NetToHost16(uint16_t x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32_t NetToHost32(uint32_t x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64_t NetToHost64(uint64_t 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_t HostToNet16(uint16_t x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32_t HostToNet32(uint32_t x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64_t HostToNet64(uint64_t x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+
+}  // namespace base
+
+#endif  // BASE_SYS_BYTEORDER_H_
diff --git a/libchrome/base/sys_info.cc b/libchrome/base/sys_info.cc
new file mode 100644
index 0000000..5aac9b7
--- /dev/null
+++ b/libchrome/base/sys_info.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/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"
+#include "build/build_config.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 (StartsWith(group_name, "Enabled", CompareCase::SENSITIVE))
+    return true;
+
+  return g_lazy_low_end_device.Get().value();
+}
+#endif
+
+#if (!defined(OS_MACOSX) || defined(OS_IOS)) && !defined(OS_ANDROID)
+std::string SysInfo::HardwareModelName() {
+  return std::string();
+}
+#endif
+
+// static
+base::TimeDelta 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_t uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
+  return base::TimeDelta::FromMicroseconds(uptime_in_microseconds);
+}
+
+}  // namespace base
diff --git a/libchrome/base/sys_info.h b/libchrome/base/sys_info.h
new file mode 100644
index 0000000..b107477
--- /dev/null
+++ b/libchrome/base/sys_info.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_SYS_INFO_H_
+#define BASE_SYS_INFO_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <string>
+
+#include "base/base_export.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_t AmountOfPhysicalMemory();
+
+  // Return the number of bytes of current available physical memory on the
+  // machine.
+  static int64_t 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_t 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_t AmountOfFreeDiskSpace(const FilePath& path);
+
+  // Return the total disk space in bytes on the volume containing |path|, or -1
+  // on failure.
+  static int64_t AmountOfTotalDiskSpace(const FilePath& path);
+
+  // Returns system uptime.
+  static TimeDelta Uptime();
+
+  // Returns a descriptive string for the current machine model or an empty
+  // string if the machine model is unknown or an error occured.
+  // e.g. "MacPro1,1" on Mac, or "Nexus 5" on Android. Only implemented on OS X,
+  // Android, and Chrome OS. This returns 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_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* 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_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();
+
+  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/libchrome/base/sys_info_chromeos.cc b/libchrome/base/sys_info_chromeos.cc
new file mode 100644
index 0000000..3794ed9
--- /dev/null
+++ b/libchrome/base/sys_info_chromeos.cc
@@ -0,0 +1,222 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.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/macros.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;
+    std::unique_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_t* major_version,
+                         int32_t* minor_version,
+                         int32_t* 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_t major_version_;
+  int32_t minor_version_;
+  int32_t 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_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* 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) {
+  std::unique_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/libchrome/base/sys_info_internal.h b/libchrome/base/sys_info_internal.h
new file mode 100644
index 0000000..a179219
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/sys_info_linux.cc b/libchrome/base/sys_info_linux.cc
new file mode 100644
index 0000000..298d245
--- /dev/null
+++ b/libchrome/base/sys_info_linux.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/sys_info.h"
+
+#include <stddef.h>
+#include <stdint.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"
+#include "build/build_config.h"
+
+namespace {
+
+int64_t 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_t>(pages) * page_size;
+}
+
+int64_t AmountOfPhysicalMemory() {
+  return AmountOfMemory(_SC_PHYS_PAGES);
+}
+
+base::LazyInstance<
+    base::internal::LazySysInfoValue<int64_t, AmountOfPhysicalMemory>>::Leaky
+    g_lazy_physical_memory = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+// static
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
+  return AmountOfMemory(_SC_AVPHYS_PAGES);
+}
+
+// static
+int64_t SysInfo::AmountOfPhysicalMemory() {
+  return g_lazy_physical_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/libchrome/base/sys_info_mac.mm b/libchrome/base/sys_info_mac.mm
new file mode 100644
index 0000000..102d99f
--- /dev/null
+++ b/libchrome/base/sys_info_mac.mm
@@ -0,0 +1,126 @@
+// Copyright 2016 The Chromium Authors. All 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>
+#import <Foundation/Foundation.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_mach_port.h"
+#import "base/mac/sdk_forward_declarations.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  return "Mac OS X";
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  int32_t major, minor, bugfix;
+  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+  return base::StringPrintf("%d.%d.%d", major, minor, bugfix);
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+                                            int32_t* minor_version,
+                                            int32_t* bugfix_version) {
+#if defined(MAC_OS_X_VERSION_10_10)
+  NSProcessInfo* processInfo = [NSProcessInfo processInfo];
+  if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) {
+    NSOperatingSystemVersion version = [processInfo operatingSystemVersion];
+    *major_version = version.majorVersion;
+    *minor_version = version.minorVersion;
+    *bugfix_version = version.patchVersion;
+  } else {
+#else
+  // Android buildbots are too old and have trouble using the forward
+  // declarations for some reason. Conditionally-compile the above block
+  // only when building on a more modern version of OS X.
+  if (true) {
+#endif
+    // -[NSProcessInfo operatingSystemVersion] is documented available in 10.10.
+    // It's also available via a private API since 10.9.2. For the remaining
+    // cases in 10.9, rely on ::Gestalt(..). Since this code is only needed for
+    // 10.9.0 and 10.9.1 and uses the recommended replacement thereafter,
+    // suppress the warning for this fallback case.
+    DCHECK(base::mac::IsOSMavericks());
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    Gestalt(gestaltSystemVersionMajor,
+            reinterpret_cast<SInt32*>(major_version));
+    Gestalt(gestaltSystemVersionMinor,
+            reinterpret_cast<SInt32*>(minor_version));
+    Gestalt(gestaltSystemVersionBugFix,
+            reinterpret_cast<SInt32*>(bugfix_version));
+#pragma clang diagnostic pop
+  }
+}
+
+// static
+int64_t 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.get(),
+                         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_t>(hostinfo.max_mem);
+}
+
+// static
+int64_t 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_t>(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/libchrome/base/sys_info_posix.cc b/libchrome/base/sys_info_posix.cc
new file mode 100644
index 0000000..5d1c450
--- /dev/null
+++ b/libchrome/base/sys_info_posix.cc
@@ -0,0 +1,170 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <unistd.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"
+#include "build/build_config.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_t 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_t, AmountOfVirtualMemory>>::Leaky
+    g_lazy_virtual_memory = LAZY_INSTANCE_INITIALIZER;
+
+bool GetDiskSpaceInfo(const base::FilePath& path,
+                      int64_t* available_bytes,
+                      int64_t* total_bytes) {
+  struct statvfs stats;
+  if (HANDLE_EINTR(statvfs(path.value().c_str(), &stats)) != 0)
+    return false;
+
+  if (available_bytes)
+    *available_bytes = static_cast<int64_t>(stats.f_bavail) * stats.f_frsize;
+  if (total_bytes)
+    *total_bytes = static_cast<int64_t>(stats.f_blocks) * stats.f_frsize;
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+#if !defined(OS_OPENBSD)
+int SysInfo::NumberOfProcessors() {
+  return g_lazy_number_of_processors.Get().value();
+}
+#endif
+
+// static
+int64_t SysInfo::AmountOfVirtualMemory() {
+  return g_lazy_virtual_memory.Get().value();
+}
+
+// static
+int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  int64_t available;
+  if (!GetDiskSpaceInfo(path, &available, nullptr))
+    return -1;
+  return available;
+}
+
+// static
+int64_t SysInfo::AmountOfTotalDiskSpace(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  int64_t total;
+  if (!GetDiskSpaceInfo(path, nullptr, &total))
+    return -1;
+  return total;
+}
+
+#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/libchrome/base/sys_info_unittest.cc b/libchrome/base/sys_info_unittest.cc
new file mode 100644
index 0000000..0231df6
--- /dev/null
+++ b/libchrome/base/sys_info_unittest.cc
@@ -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.
+
+#include <stdint.h>
+
+#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 "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest SysInfoTest;
+using base::FilePath;
+
+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_GE(base::SysInfo::AmountOfFreeDiskSpace(tmp_path), 0)
+            << tmp_path.value();
+}
+
+TEST_F(SysInfoTest, AmountOfTotalDiskSpace) {
+  // 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::AmountOfTotalDiskSpace(tmp_path), 0)
+            << tmp_path.value();
+}
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
+  int32_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t 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) {
+  base::TimeDelta 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));
+  base::TimeDelta up_time_2 = base::SysInfo::Uptime();
+  EXPECT_GT(up_time_1.InMicroseconds(), 0);
+  EXPECT_GT(up_time_2.InMicroseconds(), up_time_1.InMicroseconds());
+}
+
+#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_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t 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_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t 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_t os_major_version = -1;
+  int32_t os_minor_version = -1;
+  int32_t 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/libchrome/base/task/cancelable_task_tracker.cc b/libchrome/base/task/cancelable_task_tracker.cc
new file mode 100644
index 0000000..6f39410
--- /dev/null
+++ b/libchrome/base/task/cancelable_task_tracker.cc
@@ -0,0 +1,191 @@
+// 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 <stddef.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/threading/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_t 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_t 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,
+               RetainedRef(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/libchrome/base/task/cancelable_task_tracker.h b/libchrome/base/task/cancelable_task_tracker.h
new file mode 100644
index 0000000..86b5a45
--- /dev/null
+++ b/libchrome/base/task/cancelable_task_tracker.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.
+
+// 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 <stdint.h>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.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_t 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/libchrome/base/task/cancelable_task_tracker_unittest.cc b/libchrome/base/task/cancelable_task_tracker_unittest.cc
new file mode 100644
index 0000000..ff9e40b
--- /dev/null
+++ b/libchrome/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/libchrome/base/task_runner.cc b/libchrome/base/task_runner.cc
new file mode 100644
index 0000000..262e1f8
--- /dev/null
+++ b/libchrome/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/libchrome/base/task_runner.h b/libchrome/base/task_runner.h
new file mode 100644
index 0000000..9593835
--- /dev/null
+++ b/libchrome/base/task_runner.h
@@ -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.
+
+#ifndef BASE_TASK_RUNNER_H_
+#define BASE_TASK_RUNNER_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+
+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_.task_runner()->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/libchrome/base/task_runner_util.h b/libchrome/base/task_runner_util.h
new file mode 100644
index 0000000..ba8e120
--- /dev/null
+++ b/libchrome/base/task_runner_util.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/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(std::move(*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_.task_runner(),
+//     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/libchrome/base/task_runner_util_unittest.cc b/libchrome/base/task_runner_util_unittest.cc
new file mode 100644
index 0000000..1df5436
--- /dev/null
+++ b/libchrome/base/task_runner_util_unittest.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/task_runner_util.h"
+
+#include <utility>
+
+#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;
+  }
+};
+
+std::unique_ptr<Foo> CreateFoo() {
+  return std::unique_ptr<Foo>(new Foo);
+}
+
+void ExpectFoo(std::unique_ptr<Foo> foo) {
+  EXPECT_TRUE(foo.get());
+  std::unique_ptr<Foo> local_foo(std::move(foo));
+  EXPECT_TRUE(local_foo.get());
+  EXPECT_FALSE(foo.get());
+}
+
+struct FooDeleter {
+  void operator()(Foo* foo) const {
+    ++g_foo_free_count;
+    delete foo;
+  };
+};
+
+std::unique_ptr<Foo, FooDeleter> CreateScopedFoo() {
+  return std::unique_ptr<Foo, FooDeleter>(new Foo);
+}
+
+void ExpectScopedFoo(std::unique_ptr<Foo, FooDeleter> foo) {
+  EXPECT_TRUE(foo.get());
+  std::unique_ptr<Foo, FooDeleter> local_foo(std::move(foo));
+  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/libchrome/base/task_scheduler/OWNERS b/libchrome/base/task_scheduler/OWNERS
new file mode 100644
index 0000000..e4b383c
--- /dev/null
+++ b/libchrome/base/task_scheduler/OWNERS
@@ -0,0 +1,3 @@
+fdoray@chromium.org
+gab@chromium.org
+robliao@chromium.org
diff --git a/libchrome/base/task_scheduler/scheduler_lock.h b/libchrome/base/task_scheduler/scheduler_lock.h
new file mode 100644
index 0000000..c969eb1
--- /dev/null
+++ b/libchrome/base/task_scheduler/scheduler_lock.h
@@ -0,0 +1,88 @@
+// Copyright 2016 The Chromium Authors. All 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_SCHEDULER_SCHEDULER_LOCK_H
+#define BASE_TASK_SCHEDULER_SCHEDULER_LOCK_H
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/task_scheduler/scheduler_lock_impl.h"
+
+namespace base {
+namespace internal {
+
+// SchedulerLock should be used anywhere a lock would be used in the scheduler.
+// When DCHECK_IS_ON(), lock checking occurs. Otherwise, SchedulerLock is
+// equivalent to base::Lock.
+//
+// The shape of SchedulerLock is as follows:
+// SchedulerLock()
+//     Default constructor, no predecessor lock.
+//     DCHECKs
+//         On Acquisition if any scheduler lock is acquired on this thread.
+//
+// SchedulerLock(const SchedulerLock* predecessor)
+//     Constructor that specifies an allowed predecessor for that lock.
+//     DCHECKs
+//         On Construction if |predecessor| forms a predecessor lock cycle.
+//         On Acquisition if the previous lock acquired on the thread is not
+//             |predecessor|. Okay if there was no previous lock acquired.
+//
+// void Acquire()
+//     Acquires the lock.
+//
+// void Release()
+//     Releases the lock.
+//
+// void AssertAcquired().
+//     DCHECKs if the lock is not acquired.
+//
+// std::unique_ptr<ConditionVariable> CreateConditionVariable()
+//     Creates a condition variable using this as a lock.
+
+#if DCHECK_IS_ON()
+class SchedulerLock : public SchedulerLockImpl {
+ public:
+  SchedulerLock() = default;
+  explicit SchedulerLock(const SchedulerLock* predecessor)
+      : SchedulerLockImpl(predecessor) {}
+};
+#else  // DCHECK_IS_ON()
+class SchedulerLock : public Lock {
+ public:
+  SchedulerLock() = default;
+  explicit SchedulerLock(const SchedulerLock*) {}
+
+  std::unique_ptr<ConditionVariable> CreateConditionVariable() {
+    return std::unique_ptr<ConditionVariable>(new ConditionVariable(this));
+  }
+};
+#endif  // DCHECK_IS_ON()
+
+// Provides the same functionality as base::AutoLock for SchedulerLock.
+class AutoSchedulerLock {
+ public:
+  explicit AutoSchedulerLock(SchedulerLock& lock) : lock_(lock) {
+    lock_.Acquire();
+  }
+
+  ~AutoSchedulerLock() {
+    lock_.AssertAcquired();
+    lock_.Release();
+  }
+
+ private:
+  SchedulerLock& lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutoSchedulerLock);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_TASK_SCHEDULER_SCHEDULER_LOCK_H
diff --git a/libchrome/base/task_scheduler/scheduler_lock_impl.cc b/libchrome/base/task_scheduler/scheduler_lock_impl.cc
new file mode 100644
index 0000000..7480e18
--- /dev/null
+++ b/libchrome/base/task_scheduler/scheduler_lock_impl.cc
@@ -0,0 +1,145 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/scheduler_lock_impl.h"
+
+#include <algorithm>
+#include <unordered_map>
+#include <vector>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+class SafeAcquisitionTracker {
+ public:
+  SafeAcquisitionTracker() : tls_acquired_locks_(&OnTLSDestroy) {}
+
+  void RegisterLock(
+      const SchedulerLockImpl* const lock,
+      const SchedulerLockImpl* const predecessor) {
+    DCHECK_NE(lock, predecessor) << "Reentrant locks are unsupported.";
+    AutoLock auto_lock(allowed_predecessor_map_lock_);
+    allowed_predecessor_map_[lock] = predecessor;
+    AssertSafePredecessor(lock);
+  }
+
+  void UnregisterLock(const SchedulerLockImpl* const lock) {
+    AutoLock auto_lock(allowed_predecessor_map_lock_);
+    allowed_predecessor_map_.erase(lock);
+  }
+
+  void RecordAcquisition(const SchedulerLockImpl* const lock) {
+    AssertSafeAcquire(lock);
+    GetAcquiredLocksOnCurrentThread()->push_back(lock);
+  }
+
+  void RecordRelease(const SchedulerLockImpl* const lock) {
+    LockVector* acquired_locks = GetAcquiredLocksOnCurrentThread();
+    const auto iter_at_lock =
+        std::find(acquired_locks->begin(), acquired_locks->end(), lock);
+    DCHECK(iter_at_lock != acquired_locks->end());
+    acquired_locks->erase(iter_at_lock);
+  }
+
+ private:
+  using LockVector = std::vector<const SchedulerLockImpl*>;
+  using PredecessorMap = std::unordered_map<
+      const SchedulerLockImpl*, const SchedulerLockImpl*>;
+
+  // This asserts that the lock is safe to acquire. This means that this should
+  // be run before actually recording the acquisition.
+  void AssertSafeAcquire(const SchedulerLockImpl* const lock) {
+    const LockVector* acquired_locks = GetAcquiredLocksOnCurrentThread();
+
+    // If the thread currently holds no locks, this is inherently safe.
+    if (acquired_locks->empty())
+      return;
+
+    // Otherwise, make sure that the previous lock acquired is an allowed
+    // predecessor.
+    AutoLock auto_lock(allowed_predecessor_map_lock_);
+    const SchedulerLockImpl* allowed_predecessor =
+        allowed_predecessor_map_.at(lock);
+    DCHECK_EQ(acquired_locks->back(), allowed_predecessor);
+  }
+
+  void AssertSafePredecessor(const SchedulerLockImpl* lock) const {
+    allowed_predecessor_map_lock_.AssertAcquired();
+    for (const SchedulerLockImpl* predecessor =
+             allowed_predecessor_map_.at(lock);
+         predecessor != nullptr;
+         predecessor = allowed_predecessor_map_.at(predecessor)) {
+      DCHECK_NE(predecessor, lock) <<
+          "Scheduler lock predecessor cycle detected.";
+    }
+  }
+
+  LockVector* GetAcquiredLocksOnCurrentThread() {
+    if (!tls_acquired_locks_.Get())
+      tls_acquired_locks_.Set(new LockVector);
+
+    return reinterpret_cast<LockVector*>(tls_acquired_locks_.Get());
+  }
+
+  static void OnTLSDestroy(void* value) {
+    delete reinterpret_cast<LockVector*>(value);
+  }
+
+  // Synchronizes access to |allowed_predecessor_map_|.
+  Lock allowed_predecessor_map_lock_;
+
+  // A map of allowed predecessors.
+  PredecessorMap allowed_predecessor_map_;
+
+  // A thread-local slot holding a vector of locks currently acquired on the
+  // current thread.
+  ThreadLocalStorage::Slot tls_acquired_locks_;
+
+  DISALLOW_COPY_AND_ASSIGN(SafeAcquisitionTracker);
+};
+
+LazyInstance<SafeAcquisitionTracker>::Leaky g_safe_acquisition_tracker =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+SchedulerLockImpl::SchedulerLockImpl() : SchedulerLockImpl(nullptr) {}
+
+SchedulerLockImpl::SchedulerLockImpl(const SchedulerLockImpl* predecessor) {
+  g_safe_acquisition_tracker.Get().RegisterLock(this, predecessor);
+}
+
+SchedulerLockImpl::~SchedulerLockImpl() {
+  g_safe_acquisition_tracker.Get().UnregisterLock(this);
+}
+
+void SchedulerLockImpl::Acquire() {
+  lock_.Acquire();
+  g_safe_acquisition_tracker.Get().RecordAcquisition(this);
+}
+
+void SchedulerLockImpl::Release() {
+  lock_.Release();
+  g_safe_acquisition_tracker.Get().RecordRelease(this);
+}
+
+void SchedulerLockImpl::AssertAcquired() const {
+  lock_.AssertAcquired();
+}
+
+std::unique_ptr<ConditionVariable>
+SchedulerLockImpl::CreateConditionVariable() {
+  return std::unique_ptr<ConditionVariable>(new ConditionVariable(&lock_));
+}
+
+}  // namespace internal
+}  // base
diff --git a/libchrome/base/task_scheduler/scheduler_lock_impl.h b/libchrome/base/task_scheduler/scheduler_lock_impl.h
new file mode 100644
index 0000000..65699bb
--- /dev/null
+++ b/libchrome/base/task_scheduler/scheduler_lock_impl.h
@@ -0,0 +1,46 @@
+// Copyright 2016 The Chromium Authors. All 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_SCHEDULER_SCHEDULER_LOCK_IMPL_H
+#define BASE_TASK_SCHEDULER_SCHEDULER_LOCK_IMPL_H
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class ConditionVariable;
+
+namespace internal {
+
+// A regular lock with simple deadlock correctness checking.
+// This lock tracks all of the available locks to make sure that any locks are
+// acquired in an expected order.
+// See scheduler_lock.h for details.
+class BASE_EXPORT SchedulerLockImpl {
+ public:
+  SchedulerLockImpl();
+  explicit SchedulerLockImpl(const SchedulerLockImpl* predecessor);
+  ~SchedulerLockImpl();
+
+  void Acquire();
+  void Release();
+
+  void AssertAcquired() const;
+
+  std::unique_ptr<ConditionVariable> CreateConditionVariable();
+
+ private:
+  Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(SchedulerLockImpl);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_TASK_SCHEDULER_SCHEDULER_LOCK_IMPL_H
diff --git a/libchrome/base/task_scheduler/scheduler_lock_unittest.cc b/libchrome/base/task_scheduler/scheduler_lock_unittest.cc
new file mode 100644
index 0000000..daa5025
--- /dev/null
+++ b/libchrome/base/task_scheduler/scheduler_lock_unittest.cc
@@ -0,0 +1,296 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/scheduler_lock.h"
+
+#include <stdlib.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/rand_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/task_scheduler/test_utils.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace internal {
+namespace {
+
+// Adapted from base::Lock's BasicLockTestThread to make sure
+// Acquire()/Release() don't crash.
+class BasicLockTestThread : public SimpleThread {
+ public:
+  explicit BasicLockTestThread(SchedulerLock* lock)
+      : SimpleThread("BasicLockTestThread"),
+        lock_(lock),
+        acquired_(0) {}
+
+  int acquired() const { return acquired_; }
+
+ private:
+  void Run() 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(base::RandInt(0, 19)));
+      lock_->Release();
+    }
+  }
+
+  SchedulerLock* const lock_;
+  int acquired_;
+
+  DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
+};
+
+class BasicLockAcquireAndWaitThread : public SimpleThread {
+ public:
+  explicit BasicLockAcquireAndWaitThread(SchedulerLock* lock)
+      : SimpleThread("BasicLockAcquireAndWaitThread"),
+        lock_(lock),
+        lock_acquire_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
+                            WaitableEvent::InitialState::NOT_SIGNALED),
+        main_thread_continue_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                    WaitableEvent::InitialState::NOT_SIGNALED) {
+  }
+
+  void WaitForLockAcquisition() {
+    lock_acquire_event_.Wait();
+  }
+
+  void ContinueMain() {
+    main_thread_continue_event_.Signal();
+  }
+
+ private:
+  void Run() override {
+    lock_->Acquire();
+    lock_acquire_event_.Signal();
+    main_thread_continue_event_.Wait();
+    lock_->Release();
+  }
+
+  SchedulerLock* const lock_;
+  WaitableEvent lock_acquire_event_;
+  WaitableEvent main_thread_continue_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(BasicLockAcquireAndWaitThread);
+};
+
+TEST(TaskSchedulerLock, Basic) {
+  SchedulerLock lock;
+  BasicLockTestThread thread(&lock);
+
+  thread.Start();
+
+  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(base::RandInt(0, 19)));
+    lock.Release();
+  }
+  for (int i = 0; i < 5; i++) {
+    lock.Acquire();
+    acquired++;
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19)));
+    lock.Release();
+  }
+
+  thread.Join();
+
+  EXPECT_EQ(acquired, 20);
+  EXPECT_EQ(thread.acquired(), 20);
+}
+
+TEST(TaskSchedulerLock, AcquirePredecessor) {
+  SchedulerLock predecessor;
+  SchedulerLock lock(&predecessor);
+  predecessor.Acquire();
+  lock.Acquire();
+  lock.Release();
+  predecessor.Release();
+}
+
+TEST(TaskSchedulerLock, AcquirePredecessorWrongOrder) {
+  SchedulerLock predecessor;
+  SchedulerLock lock(&predecessor);
+  EXPECT_DCHECK_DEATH({
+    lock.Acquire();
+    predecessor.Acquire();
+  }, "");
+}
+
+TEST(TaskSchedulerLock, AcquireNonPredecessor) {
+  SchedulerLock lock1;
+  SchedulerLock lock2;
+  EXPECT_DCHECK_DEATH({
+    lock1.Acquire();
+    lock2.Acquire();
+  }, "");
+}
+
+TEST(TaskSchedulerLock, AcquireMultipleLocksInOrder) {
+  SchedulerLock lock1;
+  SchedulerLock lock2(&lock1);
+  SchedulerLock lock3(&lock2);
+  lock1.Acquire();
+  lock2.Acquire();
+  lock3.Acquire();
+  lock3.Release();
+  lock2.Release();
+  lock1.Release();
+}
+
+TEST(TaskSchedulerLock, AcquireMultipleLocksInTheMiddleOfAChain) {
+  SchedulerLock lock1;
+  SchedulerLock lock2(&lock1);
+  SchedulerLock lock3(&lock2);
+  lock2.Acquire();
+  lock3.Acquire();
+  lock3.Release();
+  lock2.Release();
+}
+
+TEST(TaskSchedulerLock, AcquireMultipleLocksNoTransitivity) {
+  SchedulerLock lock1;
+  SchedulerLock lock2(&lock1);
+  SchedulerLock lock3(&lock2);
+  EXPECT_DCHECK_DEATH({
+    lock1.Acquire();
+    lock3.Acquire();
+  }, "");
+}
+
+TEST(TaskSchedulerLock, AcquireLocksDifferentThreadsSafely) {
+  SchedulerLock lock1;
+  SchedulerLock lock2;
+  BasicLockAcquireAndWaitThread thread(&lock1);
+  thread.Start();
+
+  lock2.Acquire();
+  thread.WaitForLockAcquisition();
+  thread.ContinueMain();
+  thread.Join();
+  lock2.Release();
+}
+
+TEST(TaskSchedulerLock,
+     AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorFirst) {
+  // A lock and its predecessor may be safely acquired on different threads.
+  // This Thread                Other Thread
+  // predecessor.Acquire()
+  //                            lock.Acquire()
+  // predecessor.Release()
+  //                            lock.Release()
+  SchedulerLock predecessor;
+  SchedulerLock lock(&predecessor);
+  predecessor.Acquire();
+  BasicLockAcquireAndWaitThread thread(&lock);
+  thread.Start();
+  thread.WaitForLockAcquisition();
+  predecessor.Release();
+  thread.ContinueMain();
+  thread.Join();
+}
+
+TEST(TaskSchedulerLock,
+     AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorLast) {
+  // A lock and its predecessor may be safely acquired on different threads.
+  // This Thread                Other Thread
+  // lock.Acquire()
+  //                            predecessor.Acquire()
+  // lock.Release()
+  //                            predecessor.Release()
+  SchedulerLock predecessor;
+  SchedulerLock lock(&predecessor);
+  lock.Acquire();
+  BasicLockAcquireAndWaitThread thread(&predecessor);
+  thread.Start();
+  thread.WaitForLockAcquisition();
+  lock.Release();
+  thread.ContinueMain();
+  thread.Join();
+}
+
+TEST(TaskSchedulerLock,
+     AcquireLocksWithPredecessorDifferentThreadsSafelyNoInterference) {
+  // Acquisition of an unrelated lock on another thread should not affect a
+  // legal lock acquisition with a predecessor on this thread.
+  // This Thread                Other Thread
+  // predecessor.Acquire()
+  //                            unrelated.Acquire()
+  // lock.Acquire()
+  //                            unrelated.Release()
+  // lock.Release()
+  // predecessor.Release();
+  SchedulerLock predecessor;
+  SchedulerLock lock(&predecessor);
+  predecessor.Acquire();
+  SchedulerLock unrelated;
+  BasicLockAcquireAndWaitThread thread(&unrelated);
+  thread.Start();
+  thread.WaitForLockAcquisition();
+  lock.Acquire();
+  thread.ContinueMain();
+  thread.Join();
+  lock.Release();
+  predecessor.Release();
+}
+
+TEST(TaskSchedulerLock, SelfReferentialLock) {
+  struct SelfReferentialLock {
+    SelfReferentialLock() : lock(&lock) {}
+
+    SchedulerLock lock;
+  };
+
+  EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; }, "");
+}
+
+TEST(TaskSchedulerLock, PredecessorCycle) {
+  struct LockCycle {
+    LockCycle() : lock1(&lock2), lock2(&lock1) {}
+
+    SchedulerLock lock1;
+    SchedulerLock lock2;
+  };
+
+  EXPECT_DCHECK_DEATH({ LockCycle cycle; }, "");
+}
+
+TEST(TaskSchedulerLock, PredecessorLongerCycle) {
+  struct LockCycle {
+    LockCycle()
+        : lock1(&lock5),
+          lock2(&lock1),
+          lock3(&lock2),
+          lock4(&lock3),
+          lock5(&lock4) {}
+
+    SchedulerLock lock1;
+    SchedulerLock lock2;
+    SchedulerLock lock3;
+    SchedulerLock lock4;
+    SchedulerLock lock5;
+  };
+
+  EXPECT_DCHECK_DEATH({ LockCycle cycle; }, "");
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/task_scheduler/sequence.cc b/libchrome/base/task_scheduler/sequence.cc
new file mode 100644
index 0000000..4ecb605
--- /dev/null
+++ b/libchrome/base/task_scheduler/sequence.cc
@@ -0,0 +1,79 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/sequence.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+Sequence::Sequence() = default;
+
+bool Sequence::PushTask(std::unique_ptr<Task> task) {
+  DCHECK(task->sequenced_time.is_null());
+  task->sequenced_time = base::TimeTicks::Now();
+
+  AutoSchedulerLock auto_lock(lock_);
+  ++num_tasks_per_priority_[static_cast<int>(task->traits.priority())];
+  queue_.push(std::move(task));
+
+  // Return true if the sequence was empty before the push.
+  return queue_.size() == 1;
+}
+
+const Task* Sequence::PeekTask() const {
+  AutoSchedulerLock auto_lock(lock_);
+
+  if (queue_.empty())
+    return nullptr;
+
+  return queue_.front().get();
+}
+
+bool Sequence::PopTask() {
+  AutoSchedulerLock auto_lock(lock_);
+  DCHECK(!queue_.empty());
+
+  const int priority_index =
+      static_cast<int>(queue_.front()->traits.priority());
+  DCHECK_GT(num_tasks_per_priority_[priority_index], 0U);
+  --num_tasks_per_priority_[priority_index];
+
+  queue_.pop();
+  return queue_.empty();
+}
+
+SequenceSortKey Sequence::GetSortKey() const {
+  TaskPriority priority = TaskPriority::LOWEST;
+  base::TimeTicks next_task_sequenced_time;
+
+  {
+    AutoSchedulerLock auto_lock(lock_);
+    DCHECK(!queue_.empty());
+
+    // Find the highest task priority in the sequence.
+    const int highest_priority_index = static_cast<int>(TaskPriority::HIGHEST);
+    const int lowest_priority_index = static_cast<int>(TaskPriority::LOWEST);
+    for (int i = highest_priority_index; i > lowest_priority_index; --i) {
+      if (num_tasks_per_priority_[i] > 0) {
+        priority = static_cast<TaskPriority>(i);
+        break;
+      }
+    }
+
+    // Save the sequenced time of the next task in the sequence.
+    next_task_sequenced_time = queue_.front()->sequenced_time;
+  }
+
+  return SequenceSortKey(priority, next_task_sequenced_time);
+}
+
+Sequence::~Sequence() = default;
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/task_scheduler/sequence.h b/libchrome/base/task_scheduler/sequence.h
new file mode 100644
index 0000000..3fa037f
--- /dev/null
+++ b/libchrome/base/task_scheduler/sequence.h
@@ -0,0 +1,79 @@
+// Copyright 2016 The Chromium Authors. All 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_SCHEDULER_SEQUENCE_H_
+#define BASE_TASK_SCHEDULER_SEQUENCE_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <queue>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_scheduler/scheduler_lock.h"
+#include "base/task_scheduler/sequence_sort_key.h"
+#include "base/task_scheduler/task.h"
+#include "base/task_scheduler/task_traits.h"
+
+namespace base {
+namespace internal {
+
+// A sequence holds tasks that must be executed in posting order.
+//
+// Note: there is a known refcounted-ownership cycle in the Scheduler
+// architecture: Sequence -> Task -> TaskRunner -> Sequence -> ...
+// This is okay so long as the other owners of Sequence (PriorityQueue and
+// SchedulerWorker in alternation and
+// SchedulerWorkerPoolImpl::SchedulerWorkerDelegateImpl::GetWork()
+// temporarily) keep running it (and taking Tasks from it as a result). A
+// dangling reference cycle would only occur should they release their reference
+// to it while it's not empty. In other words, it is only correct for them to
+// release it after PopTask() returns false to indicate it was made empty by
+// that call (in which case the next PushTask() will return true to indicate to
+// the caller that the Sequence should be re-enqueued for execution).
+//
+// This class is thread-safe.
+class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> {
+ public:
+  Sequence();
+
+  // Adds |task| at the end of the sequence's queue. Returns true if the
+  // sequence was empty before this operation.
+  bool PushTask(std::unique_ptr<Task> task);
+
+  // Returns the task in front of the sequence's queue, if any.
+  const Task* PeekTask() const;
+
+  // Removes the task in front of the sequence's queue. Returns true if the
+  // sequence is empty after this operation. Cannot be called on an empty
+  // sequence.
+  bool PopTask();
+
+  // Returns a SequenceSortKey representing the priority of the sequence. Cannot
+  // be called on an empty sequence.
+  SequenceSortKey GetSortKey() const;
+
+ private:
+  friend class RefCountedThreadSafe<Sequence>;
+  ~Sequence();
+
+  // Synchronizes access to all members.
+  mutable SchedulerLock lock_;
+
+  // Queue of tasks to execute.
+  std::queue<std::unique_ptr<Task>> queue_;
+
+  // Number of tasks contained in the sequence for each priority.
+  size_t num_tasks_per_priority_[static_cast<int>(TaskPriority::HIGHEST) + 1] =
+      {};
+
+  DISALLOW_COPY_AND_ASSIGN(Sequence);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_TASK_SCHEDULER_SEQUENCE_H_
diff --git a/libchrome/base/task_scheduler/sequence_sort_key.cc b/libchrome/base/task_scheduler/sequence_sort_key.cc
new file mode 100644
index 0000000..e356c8b
--- /dev/null
+++ b/libchrome/base/task_scheduler/sequence_sort_key.cc
@@ -0,0 +1,29 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/sequence_sort_key.h"
+
+namespace base {
+namespace internal {
+
+SequenceSortKey::SequenceSortKey(TaskPriority priority,
+                                 TimeTicks next_task_sequenced_time)
+    : priority_(priority),
+      next_task_sequenced_time_(next_task_sequenced_time) {}
+
+bool SequenceSortKey::operator<(const SequenceSortKey& other) const {
+  // This SequenceSortKey is considered less important than |other| if it has a
+  // lower priority or if it has the same priority but its next task was posted
+  // later than |other|'s.
+  const int priority_diff =
+      static_cast<int>(priority_) - static_cast<int>(other.priority_);
+  if (priority_diff < 0)
+    return true;
+  if (priority_diff > 0)
+    return false;
+  return next_task_sequenced_time_ > other.next_task_sequenced_time_;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/task_scheduler/sequence_sort_key.h b/libchrome/base/task_scheduler/sequence_sort_key.h
new file mode 100644
index 0000000..eb81708
--- /dev/null
+++ b/libchrome/base/task_scheduler/sequence_sort_key.h
@@ -0,0 +1,49 @@
+// Copyright 2016 The Chromium Authors. All 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_SCHEDULER_SEQUENCE_SORT_KEY_H_
+#define BASE_TASK_SCHEDULER_SEQUENCE_SORT_KEY_H_
+
+#include "base/base_export.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+// An immutable but assignable representation of the priority of a Sequence.
+class BASE_EXPORT SequenceSortKey final {
+ public:
+  SequenceSortKey(TaskPriority priority, TimeTicks next_task_sequenced_time);
+
+  TaskPriority priority() const { return priority_; }
+
+  bool operator<(const SequenceSortKey& other) const;
+  bool operator>(const SequenceSortKey& other) const { return other < *this; }
+
+  bool operator==(const SequenceSortKey& other) const {
+    return priority_ == other.priority_ &&
+           next_task_sequenced_time_ == other.next_task_sequenced_time_;
+  }
+  bool operator!=(const SequenceSortKey& other) const {
+    return !(other == *this);
+  };
+
+ private:
+  // The private section allows this class to keep its immutable property while
+  // being copy-assignable (i.e. instead of making its members const).
+
+  // Highest task priority in the sequence at the time this sort key was
+  // created.
+  TaskPriority priority_;
+
+  // Sequenced time of the next task to run in the sequence at the time this
+  // sort key was created.
+  TimeTicks next_task_sequenced_time_;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_TASK_SCHEDULER_SEQUENCE_SORT_KEY_H_
diff --git a/libchrome/base/task_scheduler/sequence_sort_key_unittest.cc b/libchrome/base/task_scheduler/sequence_sort_key_unittest.cc
new file mode 100644
index 0000000..2c1d80d
--- /dev/null
+++ b/libchrome/base/task_scheduler/sequence_sort_key_unittest.cc
@@ -0,0 +1,243 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/sequence_sort_key.h"
+
+#include "base/task_scheduler/task_traits.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace internal {
+
+TEST(TaskSchedulerSequenceSortKeyTest, OperatorLessThan) {
+  SequenceSortKey key_a(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_b(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_c(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_d(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_e(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_f(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(2000));
+
+  EXPECT_FALSE(key_a < key_a);
+  EXPECT_LT(key_b, key_a);
+  EXPECT_LT(key_c, key_a);
+  EXPECT_LT(key_d, key_a);
+  EXPECT_LT(key_e, key_a);
+  EXPECT_LT(key_f, key_a);
+
+  EXPECT_FALSE(key_a < key_b);
+  EXPECT_FALSE(key_b < key_b);
+  EXPECT_LT(key_c, key_b);
+  EXPECT_LT(key_d, key_b);
+  EXPECT_LT(key_e, key_b);
+  EXPECT_LT(key_f, key_b);
+
+  EXPECT_FALSE(key_a < key_c);
+  EXPECT_FALSE(key_b < key_c);
+  EXPECT_FALSE(key_c < key_c);
+  EXPECT_LT(key_d, key_c);
+  EXPECT_LT(key_e, key_c);
+  EXPECT_LT(key_f, key_c);
+
+  EXPECT_FALSE(key_a < key_d);
+  EXPECT_FALSE(key_b < key_d);
+  EXPECT_FALSE(key_c < key_d);
+  EXPECT_FALSE(key_d < key_d);
+  EXPECT_LT(key_e, key_d);
+  EXPECT_LT(key_f, key_d);
+
+  EXPECT_FALSE(key_a < key_e);
+  EXPECT_FALSE(key_b < key_e);
+  EXPECT_FALSE(key_c < key_e);
+  EXPECT_FALSE(key_d < key_e);
+  EXPECT_FALSE(key_e < key_e);
+  EXPECT_LT(key_f, key_e);
+
+  EXPECT_FALSE(key_a < key_f);
+  EXPECT_FALSE(key_b < key_f);
+  EXPECT_FALSE(key_c < key_f);
+  EXPECT_FALSE(key_d < key_f);
+  EXPECT_FALSE(key_e < key_f);
+  EXPECT_FALSE(key_f < key_f);
+}
+
+TEST(TaskSchedulerSequenceSortKeyTest, OperatorGreaterThan) {
+  SequenceSortKey key_a(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_b(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_c(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_d(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_e(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_f(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(2000));
+
+  EXPECT_FALSE(key_a > key_a);
+  EXPECT_FALSE(key_b > key_a);
+  EXPECT_FALSE(key_c > key_a);
+  EXPECT_FALSE(key_d > key_a);
+  EXPECT_FALSE(key_e > key_a);
+  EXPECT_FALSE(key_f > key_a);
+
+  EXPECT_GT(key_a, key_b);
+  EXPECT_FALSE(key_b > key_b);
+  EXPECT_FALSE(key_c > key_b);
+  EXPECT_FALSE(key_d > key_b);
+  EXPECT_FALSE(key_e > key_b);
+  EXPECT_FALSE(key_f > key_b);
+
+  EXPECT_GT(key_a, key_c);
+  EXPECT_GT(key_b, key_c);
+  EXPECT_FALSE(key_c > key_c);
+  EXPECT_FALSE(key_d > key_c);
+  EXPECT_FALSE(key_e > key_c);
+  EXPECT_FALSE(key_f > key_c);
+
+  EXPECT_GT(key_a, key_d);
+  EXPECT_GT(key_b, key_d);
+  EXPECT_GT(key_c, key_d);
+  EXPECT_FALSE(key_d > key_d);
+  EXPECT_FALSE(key_e > key_d);
+  EXPECT_FALSE(key_f > key_d);
+
+  EXPECT_GT(key_a, key_e);
+  EXPECT_GT(key_b, key_e);
+  EXPECT_GT(key_c, key_e);
+  EXPECT_GT(key_d, key_e);
+  EXPECT_FALSE(key_e > key_e);
+  EXPECT_FALSE(key_f > key_e);
+
+  EXPECT_GT(key_a, key_f);
+  EXPECT_GT(key_b, key_f);
+  EXPECT_GT(key_c, key_f);
+  EXPECT_GT(key_d, key_f);
+  EXPECT_GT(key_e, key_f);
+  EXPECT_FALSE(key_f > key_f);
+}
+
+TEST(TaskSchedulerSequenceSortKeyTest, OperatorEqual) {
+  SequenceSortKey key_a(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_b(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_c(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_d(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_e(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_f(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(2000));
+
+  EXPECT_EQ(key_a, key_a);
+  EXPECT_FALSE(key_b == key_a);
+  EXPECT_FALSE(key_c == key_a);
+  EXPECT_FALSE(key_d == key_a);
+  EXPECT_FALSE(key_e == key_a);
+  EXPECT_FALSE(key_f == key_a);
+
+  EXPECT_FALSE(key_a == key_b);
+  EXPECT_EQ(key_b, key_b);
+  EXPECT_FALSE(key_c == key_b);
+  EXPECT_FALSE(key_d == key_b);
+  EXPECT_FALSE(key_e == key_b);
+  EXPECT_FALSE(key_f == key_b);
+
+  EXPECT_FALSE(key_a == key_c);
+  EXPECT_FALSE(key_b == key_c);
+  EXPECT_EQ(key_c, key_c);
+  EXPECT_FALSE(key_d == key_c);
+  EXPECT_FALSE(key_e == key_c);
+  EXPECT_FALSE(key_f == key_c);
+
+  EXPECT_FALSE(key_a == key_d);
+  EXPECT_FALSE(key_b == key_d);
+  EXPECT_FALSE(key_c == key_d);
+  EXPECT_EQ(key_d, key_d);
+  EXPECT_FALSE(key_e == key_d);
+  EXPECT_FALSE(key_f == key_d);
+
+  EXPECT_FALSE(key_a == key_e);
+  EXPECT_FALSE(key_b == key_e);
+  EXPECT_FALSE(key_c == key_e);
+  EXPECT_FALSE(key_d == key_e);
+  EXPECT_EQ(key_e, key_e);
+  EXPECT_FALSE(key_f == key_e);
+
+  EXPECT_FALSE(key_a == key_f);
+  EXPECT_FALSE(key_b == key_f);
+  EXPECT_FALSE(key_c == key_f);
+  EXPECT_FALSE(key_d == key_f);
+  EXPECT_FALSE(key_e == key_f);
+  EXPECT_EQ(key_f, key_f);
+}
+
+TEST(TaskSchedulerSequenceSortKeyTest, OperatorNotEqual) {
+  SequenceSortKey key_a(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_b(TaskPriority::USER_BLOCKING,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_c(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_d(TaskPriority::USER_VISIBLE,
+                        TimeTicks::FromInternalValue(2000));
+  SequenceSortKey key_e(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(1000));
+  SequenceSortKey key_f(TaskPriority::BACKGROUND,
+                        TimeTicks::FromInternalValue(2000));
+
+  EXPECT_FALSE(key_a != key_a);
+  EXPECT_NE(key_b, key_a);
+  EXPECT_NE(key_c, key_a);
+  EXPECT_NE(key_d, key_a);
+  EXPECT_NE(key_e, key_a);
+  EXPECT_NE(key_f, key_a);
+
+  EXPECT_NE(key_a, key_b);
+  EXPECT_FALSE(key_b != key_b);
+  EXPECT_NE(key_c, key_b);
+  EXPECT_NE(key_d, key_b);
+  EXPECT_NE(key_e, key_b);
+  EXPECT_NE(key_f, key_b);
+
+  EXPECT_NE(key_a, key_c);
+  EXPECT_NE(key_b, key_c);
+  EXPECT_FALSE(key_c != key_c);
+  EXPECT_NE(key_d, key_c);
+  EXPECT_NE(key_e, key_c);
+  EXPECT_NE(key_f, key_c);
+
+  EXPECT_NE(key_a, key_d);
+  EXPECT_NE(key_b, key_d);
+  EXPECT_NE(key_c, key_d);
+  EXPECT_FALSE(key_d != key_d);
+  EXPECT_NE(key_e, key_d);
+  EXPECT_NE(key_f, key_d);
+
+  EXPECT_NE(key_a, key_e);
+  EXPECT_NE(key_b, key_e);
+  EXPECT_NE(key_c, key_e);
+  EXPECT_NE(key_d, key_e);
+  EXPECT_FALSE(key_e != key_e);
+  EXPECT_NE(key_f, key_e);
+
+  EXPECT_NE(key_a, key_f);
+  EXPECT_NE(key_b, key_f);
+  EXPECT_NE(key_c, key_f);
+  EXPECT_NE(key_d, key_f);
+  EXPECT_NE(key_e, key_f);
+  EXPECT_FALSE(key_f != key_f);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/task_scheduler/sequence_unittest.cc b/libchrome/base/task_scheduler/sequence_unittest.cc
new file mode 100644
index 0000000..6a15299
--- /dev/null
+++ b/libchrome/base/task_scheduler/sequence_unittest.cc
@@ -0,0 +1,189 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/sequence.h"
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+class TaskSchedulerSequenceTest : public testing::Test {
+ public:
+  TaskSchedulerSequenceTest()
+      : task_a_owned_(
+            new Task(FROM_HERE,
+                     Closure(),
+                     TaskTraits().WithPriority(TaskPriority::BACKGROUND),
+                     TimeDelta())),
+        task_b_owned_(
+            new Task(FROM_HERE,
+                     Closure(),
+                     TaskTraits().WithPriority(TaskPriority::USER_VISIBLE),
+                     TimeDelta())),
+        task_c_owned_(
+            new Task(FROM_HERE,
+                     Closure(),
+                     TaskTraits().WithPriority(TaskPriority::USER_BLOCKING),
+                     TimeDelta())),
+        task_d_owned_(
+            new Task(FROM_HERE,
+                     Closure(),
+                     TaskTraits().WithPriority(TaskPriority::USER_BLOCKING),
+                     TimeDelta())),
+        task_e_owned_(
+            new Task(FROM_HERE,
+                     Closure(),
+                     TaskTraits().WithPriority(TaskPriority::BACKGROUND),
+                     TimeDelta())),
+        task_a_(task_a_owned_.get()),
+        task_b_(task_b_owned_.get()),
+        task_c_(task_c_owned_.get()),
+        task_d_(task_d_owned_.get()),
+        task_e_(task_e_owned_.get()) {}
+
+ protected:
+  // Tasks to be handed off to a Sequence for testing.
+  std::unique_ptr<Task> task_a_owned_;
+  std::unique_ptr<Task> task_b_owned_;
+  std::unique_ptr<Task> task_c_owned_;
+  std::unique_ptr<Task> task_d_owned_;
+  std::unique_ptr<Task> task_e_owned_;
+
+  // Raw pointers to those same tasks for verification. This is needed because
+  // the scoped_ptrs above no longer point to the tasks once they have been
+  // moved into a Sequence.
+  const Task* task_a_;
+  const Task* task_b_;
+  const Task* task_c_;
+  const Task* task_d_;
+  const Task* task_e_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSequenceTest);
+};
+
+}  // namespace
+
+TEST_F(TaskSchedulerSequenceTest, PushPopPeek) {
+  scoped_refptr<Sequence> sequence(new Sequence);
+
+  // Push task A in the sequence. Its sequenced time should be updated and it
+  // should be in front of the sequence.
+  EXPECT_TRUE(sequence->PushTask(std::move(task_a_owned_)));
+  EXPECT_FALSE(task_a_->sequenced_time.is_null());
+  EXPECT_EQ(task_a_, sequence->PeekTask());
+
+  // Push task B, C and D in the sequence. Their sequenced time should be
+  // updated and task A should always remain in front of the sequence.
+  EXPECT_FALSE(sequence->PushTask(std::move(task_b_owned_)));
+  EXPECT_FALSE(task_b_->sequenced_time.is_null());
+  EXPECT_EQ(task_a_, sequence->PeekTask());
+
+  EXPECT_FALSE(sequence->PushTask(std::move(task_c_owned_)));
+  EXPECT_FALSE(task_c_->sequenced_time.is_null());
+  EXPECT_EQ(task_a_, sequence->PeekTask());
+
+  EXPECT_FALSE(sequence->PushTask(std::move(task_d_owned_)));
+  EXPECT_FALSE(task_d_->sequenced_time.is_null());
+  EXPECT_EQ(task_a_, sequence->PeekTask());
+
+  // Pop task A. Task B should now be in front.
+  EXPECT_FALSE(sequence->PopTask());
+  EXPECT_EQ(task_b_, sequence->PeekTask());
+
+  // Pop task B. Task C should now be in front.
+  EXPECT_FALSE(sequence->PopTask());
+  EXPECT_EQ(task_c_, sequence->PeekTask());
+
+  // Pop task C. Task D should now be in front.
+  EXPECT_FALSE(sequence->PopTask());
+  EXPECT_EQ(task_d_, sequence->PeekTask());
+
+  // Push task E in the sequence. Its sequenced time should be updated and
+  // task D should remain in front.
+  EXPECT_FALSE(sequence->PushTask(std::move(task_e_owned_)));
+  EXPECT_FALSE(task_e_->sequenced_time.is_null());
+  EXPECT_EQ(task_d_, sequence->PeekTask());
+
+  // Pop task D. Task E should now be in front.
+  EXPECT_FALSE(sequence->PopTask());
+  EXPECT_EQ(task_e_, sequence->PeekTask());
+
+  // Pop task E. The sequence should now be empty.
+  EXPECT_TRUE(sequence->PopTask());
+  EXPECT_EQ(nullptr, sequence->PeekTask());
+}
+
+TEST_F(TaskSchedulerSequenceTest, GetSortKey) {
+  scoped_refptr<Sequence> sequence(new Sequence);
+
+  // Push task A in the sequence. The highest priority is from task A
+  // (BACKGROUND). Task A is in front of the sequence.
+  sequence->PushTask(std::move(task_a_owned_));
+  EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_a_->sequenced_time),
+            sequence->GetSortKey());
+
+  // Push task B in the sequence. The highest priority is from task B
+  // (USER_VISIBLE). Task A is still in front of the sequence.
+  sequence->PushTask(std::move(task_b_owned_));
+  EXPECT_EQ(
+      SequenceSortKey(TaskPriority::USER_VISIBLE, task_a_->sequenced_time),
+      sequence->GetSortKey());
+
+  // Push task C in the sequence. The highest priority is from task C
+  // (USER_BLOCKING). Task A is still in front of the sequence.
+  sequence->PushTask(std::move(task_c_owned_));
+  EXPECT_EQ(
+      SequenceSortKey(TaskPriority::USER_BLOCKING, task_a_->sequenced_time),
+      sequence->GetSortKey());
+
+  // Push task D in the sequence. The highest priority is from tasks C/D
+  // (USER_BLOCKING). Task A is still in front of the sequence.
+  sequence->PushTask(std::move(task_d_owned_));
+  EXPECT_EQ(
+      SequenceSortKey(TaskPriority::USER_BLOCKING, task_a_->sequenced_time),
+      sequence->GetSortKey());
+
+  // Pop task A. The highest priority is still USER_BLOCKING. The task in front
+  // of the sequence is now task B.
+  sequence->PopTask();
+  EXPECT_EQ(
+      SequenceSortKey(TaskPriority::USER_BLOCKING, task_b_->sequenced_time),
+      sequence->GetSortKey());
+
+  // Pop task B. The highest priority is still USER_BLOCKING. The task in front
+  // of the sequence is now task C.
+  sequence->PopTask();
+  EXPECT_EQ(
+      SequenceSortKey(TaskPriority::USER_BLOCKING, task_c_->sequenced_time),
+      sequence->GetSortKey());
+
+  // Pop task C. The highest priority is still USER_BLOCKING. The task in front
+  // of the sequence is now task D.
+  sequence->PopTask();
+  EXPECT_EQ(
+      SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time),
+      sequence->GetSortKey());
+
+  // Push task E in the sequence. The highest priority is still USER_BLOCKING.
+  // The task in front of the sequence is still task D.
+  sequence->PushTask(std::move(task_e_owned_));
+  EXPECT_EQ(
+      SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time),
+      sequence->GetSortKey());
+
+  // Pop task D. The highest priority is now from task E (BACKGROUND). The
+  // task in front of the sequence is now task E.
+  sequence->PopTask();
+  EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_e_->sequenced_time),
+            sequence->GetSortKey());
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/task_scheduler/task.cc b/libchrome/base/task_scheduler/task.cc
new file mode 100644
index 0000000..8a589a2
--- /dev/null
+++ b/libchrome/base/task_scheduler/task.cc
@@ -0,0 +1,23 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/task.h"
+
+namespace base {
+namespace internal {
+
+Task::Task(const tracked_objects::Location& posted_from,
+           const Closure& task,
+           const TaskTraits& traits,
+           const TimeDelta& delay)
+    : PendingTask(posted_from,
+                  task,
+                  delay.is_zero() ? TimeTicks() : TimeTicks::Now() + delay,
+                  false),  // Not nestable.
+      traits(traits) {}
+
+Task::~Task() = default;
+
+}  // namespace internal
+}  // namespace base
diff --git a/libchrome/base/task_scheduler/task.h b/libchrome/base/task_scheduler/task.h
new file mode 100644
index 0000000..2b53c69
--- /dev/null
+++ b/libchrome/base/task_scheduler/task.h
@@ -0,0 +1,64 @@
+// Copyright 2016 The Chromium Authors. All 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_SCHEDULER_TASK_H_
+#define BASE_TASK_SCHEDULER_TASK_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/pending_task.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+// A task is a unit of work inside the task scheduler. Support for tracing and
+// profiling inherited from PendingTask.
+struct BASE_EXPORT Task : public PendingTask {
+  // |posted_from| is the site the task was posted from. |task| is the closure
+  // to run. |traits| is metadata about the task. |delay| is a delay that must
+  // expire before the Task runs.
+  Task(const tracked_objects::Location& posted_from,
+       const Closure& task,
+       const TaskTraits& traits,
+       const TimeDelta& delay);
+  ~Task();
+
+  // The TaskTraits of this task.
+  const TaskTraits traits;
+
+  // The time at which the task was inserted in its sequence. For an undelayed
+  // task, this happens at post time. For a delayed task, this happens some
+  // time after the task's delay has expired. If the task hasn't been inserted
+  // in a sequence yet, this defaults to a null TimeTicks.
+  TimeTicks sequenced_time;
+
+  // A reference to the SequencedTaskRunner or SingleThreadTaskRunner that
+  // posted this task, if any. Used to set ThreadTaskRunnerHandle and/or
+  // SequencedTaskRunnerHandle while the task is running.
+  // Note: this creates an ownership cycle
+  //   Sequence -> Task -> TaskRunner -> Sequence -> ...
+  // but that's okay as it's broken when the Task is popped from its Sequence
+  // after being executed which means this cycle forces the TaskRunner to stick
+  // around until all its tasks have been executed which is a requirement to
+  // support TaskRunnerHandles.
+  scoped_refptr<SequencedTaskRunner> sequenced_task_runner_ref;
+  scoped_refptr<SingleThreadTaskRunner> single_thread_task_runner_ref;
+
+ private:
+  // Disallow copies to make sure no unnecessary ref-bumps are incurred. Making
+  // it move-only would be an option, but isn't necessary for now.
+  DISALLOW_COPY_AND_ASSIGN(Task);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_TASK_SCHEDULER_TASK_H_
diff --git a/libchrome/base/task_scheduler/task_traits.cc b/libchrome/base/task_scheduler/task_traits.cc
new file mode 100644
index 0000000..dd55535
--- /dev/null
+++ b/libchrome/base/task_scheduler/task_traits.cc
@@ -0,0 +1,70 @@
+// Copyright 2016 The Chromium Authors. All 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_scheduler/task_traits.h"
+
+#include <stddef.h>
+
+#include <ostream>
+
+namespace base {
+
+// Do not rely on defaults hard-coded below beyond the guarantees described in
+// the header; anything else is subject to change. Tasks should explicitly
+// request defaults if the behavior is critical to the task.
+TaskTraits::TaskTraits()
+    : with_file_io_(false),
+      priority_(TaskPriority::BACKGROUND),
+      shutdown_behavior_(TaskShutdownBehavior::SKIP_ON_SHUTDOWN) {}
+
+TaskTraits::~TaskTraits() = default;
+
+TaskTraits& TaskTraits::WithFileIO() {
+  with_file_io_ = true;
+  return *this;
+}
+
+TaskTraits& TaskTraits::WithPriority(TaskPriority priority) {
+  priority_ = priority;
+  return *this;
+}
+
+TaskTraits& TaskTraits::WithShutdownBehavior(
+    TaskShutdownBehavior shutdown_behavior) {
+  shutdown_behavior_ = shutdown_behavior;
+  return *this;
+}
+
+std::ostream& operator<<(std::ostream& os, const TaskPriority& task_priority) {
+  switch (task_priority) {
+    case TaskPriority::BACKGROUND:
+      os << "BACKGROUND";
+      break;
+    case TaskPriority::USER_VISIBLE:
+      os << "USER_VISIBLE";
+      break;
+    case TaskPriority::USER_BLOCKING:
+      os << "USER_BLOCKING";
+      break;
+  }
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& os,
+                         const TaskShutdownBehavior& shutdown_behavior) {
+  switch (shutdown_behavior) {
+    case TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN:
+      os << "CONTINUE_ON_SHUTDOWN";
+      break;
+    case TaskShutdownBehavior::SKIP_ON_SHUTDOWN:
+      os << "SKIP_ON_SHUTDOWN";
+      break;
+    case TaskShutdownBehavior::BLOCK_SHUTDOWN:
+      os << "BLOCK_SHUTDOWN";
+      break;
+  }
+  return os;
+}
+
+}  // namespace base
diff --git a/libchrome/base/task_scheduler/task_traits.h b/libchrome/base/task_scheduler/task_traits.h
new file mode 100644
index 0000000..0c0d304
--- /dev/null
+++ b/libchrome/base/task_scheduler/task_traits.h
@@ -0,0 +1,140 @@
+// Copyright 2016 The Chromium Authors. All 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_SCHEDULER_TASK_TRAITS_H_
+#define BASE_TASK_SCHEDULER_TASK_TRAITS_H_
+
+#include <stdint.h>
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Valid priorities supported by the task scheduler. Note: internal algorithms
+// depend on priorities being expressed as a continuous zero-based list from
+// lowest to highest priority. Users of this API shouldn't otherwise care about
+// nor use the underlying values.
+enum class TaskPriority {
+  // This will always be equal to the lowest priority available.
+  LOWEST = 0,
+  // User won't notice if this task takes an arbitrarily long time to complete.
+  BACKGROUND = LOWEST,
+  // This task affects UI or responsiveness of future user interactions. It is
+  // not an immediate response to a user interaction.
+  // Examples:
+  // - Updating the UI to reflect progress on a long task.
+  // - Loading data that might be shown in the UI after a future user
+  //   interaction.
+  USER_VISIBLE,
+  // This task affects UI immediately after a user interaction.
+  // Example: Generating data shown in the UI immediately after a click.
+  USER_BLOCKING,
+  // This will always be equal to the highest priority available.
+  HIGHEST = USER_BLOCKING,
+};
+
+// Valid shutdown behaviors supported by the task scheduler.
+enum class TaskShutdownBehavior {
+  // Tasks posted with this mode which have not started executing before
+  // shutdown is initiated will never run. Tasks with this mode running at
+  // shutdown will be ignored (the worker 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 never run. However, any task that has already begun
+  // executing when shutdown is invoked will be allowed to continue and
+  // will block shutdown until completion.
+  //
+  // Note: Because TaskScheduler::Shutdown() may block while these tasks are
+  // executing, care must be taken to ensure that they do not block on the
+  // thread that called TaskScheduler::Shutdown(), as this may lead to deadlock.
+  SKIP_ON_SHUTDOWN,
+
+  // Tasks posted with this mode before shutdown is complete will block shutdown
+  // until they're executed. Generally, this should be used only to save
+  // critical user data.
+  //
+  // Note: Tasks with BACKGROUND priority that block shutdown will be promoted
+  // to USER_VISIBLE priority during shutdown.
+  BLOCK_SHUTDOWN,
+};
+
+// Describes metadata for a single task or a group of tasks.
+class BASE_EXPORT TaskTraits {
+ public:
+  // Constructs a default TaskTraits for tasks with
+  //     (1) no I/O,
+  //     (2) low priority, and
+  //     (3) may block shutdown or be skipped on shutdown.
+  // Tasks that require stricter guarantees should highlight those by requesting
+  // explicit traits below.
+  TaskTraits();
+  TaskTraits(const TaskTraits& other) = default;
+  TaskTraits& operator=(const TaskTraits& other) = default;
+  ~TaskTraits();
+
+  // Allows tasks with these traits to do file I/O.
+  TaskTraits& WithFileIO();
+
+  // Applies |priority| to tasks with these traits.
+  TaskTraits& WithPriority(TaskPriority priority);
+
+  // Applies |shutdown_behavior| to tasks with these traits.
+  TaskTraits& WithShutdownBehavior(TaskShutdownBehavior shutdown_behavior);
+
+  // Returns true if file I/O is allowed by these traits.
+  bool with_file_io() const { return with_file_io_; }
+
+  // Returns the priority of tasks with these traits.
+  TaskPriority priority() const { return priority_; }
+
+  // Returns the shutdown behavior of tasks with these traits.
+  TaskShutdownBehavior shutdown_behavior() const { return shutdown_behavior_; }
+
+ private:
+  bool with_file_io_;
+  TaskPriority priority_;
+  TaskShutdownBehavior shutdown_behavior_;
+};
+
+// Describes how tasks are executed by a task runner.
+enum class ExecutionMode {
+  // Can execute multiple tasks at a time in any order.
+  PARALLEL,
+
+  // Executes one task at a time in posting order. The sequence’s priority is
+  // equivalent to the highest priority pending task in the sequence.
+  SEQUENCED,
+
+  // Executes one task at a time on a single thread in posting order.
+  SINGLE_THREADED,
+};
+
+// Stream operators so TaskPriority and TaskShutdownBehavior can be used in
+// DCHECK statements.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os,
+                                     const TaskPriority& shutdown_behavior);
+
+BASE_EXPORT std::ostream& operator<<(
+    std::ostream& os,
+    const TaskShutdownBehavior& shutdown_behavior);
+
+}  // namespace base
+
+#endif  // BASE_TASK_SCHEDULER_TASK_TRAITS_H_
diff --git a/libchrome/base/task_scheduler/test_utils.h b/libchrome/base/task_scheduler/test_utils.h
new file mode 100644
index 0000000..bafd09a
--- /dev/null
+++ b/libchrome/base/task_scheduler/test_utils.h
@@ -0,0 +1,19 @@
+// Copyright 2016 The Chromium Authors. All 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_SCHEDULER_TEST_UTILS_H_
+#define BASE_TASK_SCHEDULER_TEST_UTILS_H_
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Death tests misbehave on Android.
+#if DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+#define EXPECT_DCHECK_DEATH(statement, regex) EXPECT_DEATH(statement, regex)
+#else
+#define EXPECT_DCHECK_DEATH(statement, regex)
+#endif
+
+#endif  // BASE_TASK_SCHEDULER_TEST_UTILS_H_
diff --git a/libchrome/base/template_util.h b/libchrome/base/template_util.h
new file mode 100644
index 0000000..1bfc1ac
--- /dev/null
+++ b/libchrome/base/template_util.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.
+
+#ifndef BASE_TEMPLATE_UTIL_H_
+#define BASE_TEMPLATE_UTIL_H_
+
+#include <stddef.h>
+#include <iosfwd>
+#include <type_traits>
+#include <utility>
+
+#include "build/build_config.h"
+
+// This hacks around libstdc++ 4.6 missing stuff in type_traits, while we need
+// to support it.
+#define CR_GLIBCXX_4_7_0 20120322
+#define CR_GLIBCXX_4_5_4 20120702
+#define CR_GLIBCXX_4_6_4 20121127
+#if defined(__GLIBCXX__) &&                                               \
+    (__GLIBCXX__ < CR_GLIBCXX_4_7_0 || __GLIBCXX__ == CR_GLIBCXX_4_5_4 || \
+     __GLIBCXX__ == CR_GLIBCXX_4_6_4)
+#define CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
+#endif
+
+namespace base {
+
+template <class T> struct is_non_const_reference : std::false_type {};
+template <class T> struct is_non_const_reference<T&> : std::true_type {};
+template <class T> struct is_non_const_reference<const T&> : std::false_type {};
+
+// is_assignable
+
+namespace internal {
+
+template <typename First, typename Second>
+struct SelectSecond {
+  using type = Second;
+};
+
+struct Any {
+  Any(...);
+};
+
+// True case: If |Lvalue| can be assigned to from |Rvalue|, then the return
+// value is a true_type.
+template <class Lvalue, class Rvalue>
+typename internal::SelectSecond<
+    decltype((std::declval<Lvalue>() = std::declval<Rvalue>())),
+    std::true_type>::type
+IsAssignableTest(Lvalue&&, Rvalue&&);
+
+// False case: Otherwise the return value is a false_type.
+template <class Rvalue>
+std::false_type IsAssignableTest(internal::Any, Rvalue&&);
+
+// Default case: Neither Lvalue nor Rvalue is void. Uses IsAssignableTest to
+// determine the type of IsAssignableImpl.
+template <class Lvalue,
+          class Rvalue,
+          bool = std::is_void<Lvalue>::value || std::is_void<Rvalue>::value>
+struct IsAssignableImpl
+    : public std::common_type<decltype(
+          internal::IsAssignableTest(std::declval<Lvalue>(),
+                                     std::declval<Rvalue>()))>::type {};
+
+// Void case: Either Lvalue or Rvalue is void. Then the type of IsAssignableTest
+// is false_type.
+template <class Lvalue, class Rvalue>
+struct IsAssignableImpl<Lvalue, Rvalue, true> : public std::false_type {};
+
+// Uses expression SFINAE to detect whether using operator<< would work.
+template <typename T, typename = void>
+struct SupportsOstreamOperator : std::false_type {};
+template <typename T>
+struct SupportsOstreamOperator<T,
+                               decltype(void(std::declval<std::ostream&>()
+                                             << std::declval<T>()))>
+    : std::true_type {};
+
+}  // namespace internal
+
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace.
+template <class Lvalue, class Rvalue>
+struct is_assignable : public internal::IsAssignableImpl<Lvalue, Rvalue> {};
+
+// is_copy_assignable is true if a T const& is assignable to a T&.
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace.
+template <class T>
+struct is_copy_assignable
+    : public is_assignable<typename std::add_lvalue_reference<T>::type,
+                           typename std::add_lvalue_reference<
+                               typename std::add_const<T>::type>::type> {};
+
+// is_move_assignable is true if a T&& is assignable to a T&.
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace.
+template <class T>
+struct is_move_assignable
+    : public is_assignable<typename std::add_lvalue_reference<T>::type,
+                           const typename std::add_rvalue_reference<T>::type> {
+};
+
+// underlying_type produces the integer type backing an enum type.
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace.
+#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
+template <typename T>
+struct underlying_type {
+  using type = __underlying_type(T);
+};
+#else
+template <typename T>
+using underlying_type = std::underlying_type<T>;
+#endif
+
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace.
+#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
+template <class T>
+using is_trivially_destructible = std::has_trivial_destructor<T>;
+#else
+template <class T>
+using is_trivially_destructible = std::is_trivially_destructible<T>;
+#endif
+
+}  // namespace base
+
+#undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
+
+#endif  // BASE_TEMPLATE_UTIL_H_
diff --git a/libchrome/base/template_util_unittest.cc b/libchrome/base/template_util_unittest.cc
new file mode 100644
index 0000000..9215964
--- /dev/null
+++ b/libchrome/base/template_util_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/template_util.h"
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+enum SimpleEnum { SIMPLE_ENUM };
+enum EnumWithExplicitType : uint64_t { ENUM_WITH_EXPLICIT_TYPE };
+enum class ScopedEnum { SCOPED_ENUM };
+enum class ScopedEnumWithOperator { SCOPED_ENUM_WITH_OPERATOR };
+std::ostream& operator<<(std::ostream& os, ScopedEnumWithOperator v) {
+  return os;
+}
+struct SimpleStruct {};
+struct StructWithOperator {};
+std::ostream& operator<<(std::ostream& os, const StructWithOperator& v) {
+  return os;
+}
+
+// is_non_const_reference<Type>
+static_assert(!is_non_const_reference<int>::value, "IsNonConstReference");
+static_assert(!is_non_const_reference<const int&>::value,
+              "IsNonConstReference");
+static_assert(is_non_const_reference<int&>::value, "IsNonConstReference");
+
+class AssignParent {};
+class AssignChild : AssignParent {};
+
+// is_assignable<Type1, Type2>
+static_assert(!is_assignable<int, int>::value, "IsAssignable");  // 1 = 1;
+static_assert(!is_assignable<int, double>::value, "IsAssignable");
+static_assert(is_assignable<int&, int>::value, "IsAssignable");
+static_assert(is_assignable<int&, double>::value, "IsAssignable");
+static_assert(is_assignable<int&, int&>::value, "IsAssignable");
+static_assert(is_assignable<int&, int const&>::value, "IsAssignable");
+static_assert(!is_assignable<int const&, int>::value, "IsAssignable");
+static_assert(!is_assignable<AssignParent&, AssignChild>::value,
+              "IsAssignable");
+static_assert(!is_assignable<AssignChild&, AssignParent>::value,
+              "IsAssignable");
+
+struct AssignCopy {};
+struct AssignNoCopy {
+  AssignNoCopy& operator=(AssignNoCopy&&) { return *this; }
+  AssignNoCopy& operator=(const AssignNoCopy&) = delete;
+};
+struct AssignNoMove {
+  AssignNoMove& operator=(AssignNoMove&&) = delete;
+  AssignNoMove& operator=(const AssignNoMove&) = delete;
+};
+
+static_assert(is_copy_assignable<AssignCopy>::value, "IsCopyAssignable");
+static_assert(!is_copy_assignable<AssignNoCopy>::value, "IsCopyAssignable");
+
+static_assert(is_move_assignable<AssignCopy>::value, "IsMoveAssignable");
+static_assert(is_move_assignable<AssignNoCopy>::value, "IsMoveAssignable");
+static_assert(!is_move_assignable<AssignNoMove>::value, "IsMoveAssignable");
+
+// A few standard types that definitely support printing.
+static_assert(internal::SupportsOstreamOperator<int>::value,
+              "ints should be printable");
+static_assert(internal::SupportsOstreamOperator<const char*>::value,
+              "C strings should be printable");
+static_assert(internal::SupportsOstreamOperator<std::string>::value,
+              "std::string should be printable");
+
+// Various kinds of enums operator<< support.
+static_assert(internal::SupportsOstreamOperator<SimpleEnum>::value,
+              "simple enum should be printable by value");
+static_assert(internal::SupportsOstreamOperator<const SimpleEnum&>::value,
+              "simple enum should be printable by const ref");
+static_assert(internal::SupportsOstreamOperator<EnumWithExplicitType>::value,
+              "enum with explicit type should be printable by value");
+static_assert(
+    internal::SupportsOstreamOperator<const EnumWithExplicitType&>::value,
+    "enum with explicit type should be printable by const ref");
+static_assert(!internal::SupportsOstreamOperator<ScopedEnum>::value,
+              "scoped enum should not be printable by value");
+static_assert(!internal::SupportsOstreamOperator<const ScopedEnum&>::value,
+              "simple enum should not be printable by const ref");
+static_assert(internal::SupportsOstreamOperator<ScopedEnumWithOperator>::value,
+              "scoped enum with operator<< should be printable by value");
+static_assert(
+    internal::SupportsOstreamOperator<const ScopedEnumWithOperator&>::value,
+    "scoped enum with operator<< should be printable by const ref");
+
+// operator<< support on structs.
+static_assert(!internal::SupportsOstreamOperator<SimpleStruct>::value,
+              "simple struct should not be printable by value");
+static_assert(!internal::SupportsOstreamOperator<const SimpleStruct&>::value,
+              "simple struct should not be printable by const ref");
+static_assert(internal::SupportsOstreamOperator<StructWithOperator>::value,
+              "struct with operator<< should be printable by value");
+static_assert(
+    internal::SupportsOstreamOperator<const StructWithOperator&>::value,
+    "struct with operator<< should be printable by const ref");
+
+// underlying type of enums
+static_assert(std::is_integral<underlying_type<SimpleEnum>::type>::value,
+              "simple enum must have some integral type");
+static_assert(
+    std::is_same<underlying_type<EnumWithExplicitType>::type, uint64_t>::value,
+    "explicit type must be detected");
+static_assert(std::is_same<underlying_type<ScopedEnum>::type, int>::value,
+              "scoped enum defaults to int");
+
+struct TriviallyDestructible {
+  int field;
+};
+
+class NonTriviallyDestructible {
+  ~NonTriviallyDestructible() {}
+};
+
+static_assert(is_trivially_destructible<int>::value, "IsTriviallyDestructible");
+static_assert(is_trivially_destructible<TriviallyDestructible>::value,
+              "IsTriviallyDestructible");
+static_assert(!is_trivially_destructible<NonTriviallyDestructible>::value,
+              "IsTriviallyDestructible");
+
+}  // namespace
+}  // namespace base
diff --git a/libchrome/base/test/BUILD.gn b/libchrome/base/test/BUILD.gn
new file mode 100644
index 0000000..51863a2
--- /dev/null
+++ b/libchrome/base/test/BUILD.gn
@@ -0,0 +1,279 @@
+# 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("//build/config/nacl/config.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+static_library("test_config") {
+  testonly = true
+  sources = [
+    "test_switches.cc",
+    "test_switches.h",
+    "test_timeouts.cc",
+    "test_timeouts.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+# GYP: //base/base.gyp:test_support_base
+static_library("test_support") {
+  testonly = true
+  sources = [
+    "../trace_event/trace_config_memory_test_util.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",
+    "ios/wait_util.h",
+    "ios/wait_util.mm",
+    "launcher/test_result.cc",
+    "launcher/test_result.h",
+    "launcher/test_results_tracker.h",
+    "launcher/unit_test_launcher.h",
+    "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.h",
+    "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_command_line.cc",
+    "scoped_command_line.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_message_loop.cc",
+    "test_message_loop.h",
+    "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",
+  ]
+
+  if (is_ios) {
+    sources += [ "launcher/unit_test_launcher_ios.cc" ]
+  } else if (!is_nacl_nonsfi) {
+    sources += [
+      "launcher/test_launcher.cc",
+      "launcher/test_launcher.h",
+      "launcher/test_launcher_tracer.cc",
+      "launcher/test_launcher_tracer.h",
+      "launcher/test_results_tracker.cc",
+      "launcher/unit_test_launcher.cc",
+      "multiprocess_test.cc",
+      "multiprocess_test_android.cc",
+    ]
+  }
+
+  configs += [ "//build/config:precompiled_headers" ]
+
+  data = [
+    # The isolate needs this script for setting up the test. It's not actually
+    # needed to run this target locally.
+    "//testing/test_env.py",
+  ]
+
+  public_deps = [
+    ":test_config",
+    "//base",
+    "//base:base_static",
+    "//base:i18n",
+  ]
+  deps = [
+    "//base/third_party/dynamic_annotations",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/icu:icuuc",
+    "//third_party/libxml",
+  ]
+
+  if (!is_posix) {
+    sources -= [
+      "scoped_locale.cc",
+      "scoped_locale.h",
+    ]
+  }
+
+  if (is_ios) {
+    set_sources_assignment_filter([])
+    sources += [ "test_file_util_mac.cc" ]
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  if (is_mac) {
+    libs = [ "AppKit.framework" ]
+  }
+
+  if (is_android) {
+    deps += [ ":base_unittests_jni_headers" ]
+  }
+
+  if (is_nacl_nonsfi) {
+    sources += [
+      "launcher/test_launcher.h",
+      "launcher/test_result.h",
+      "launcher/unit_test_launcher.h",
+      "launcher/unit_test_launcher_nacl_nonsfi.cc",
+    ]
+    sources -= [
+      "gtest_xml_util.cc",
+      "gtest_xml_util.h",
+      "perf_test_suite.cc",
+      "perf_test_suite.h",
+      "scoped_path_override.cc",
+      "scoped_path_override.h",
+      "test_discardable_memory_allocator.cc",
+      "test_discardable_memory_allocator.h",
+      "test_file_util.cc",
+      "test_file_util.h",
+      "test_file_util_posix.cc",
+      "test_suite.cc",
+      "test_suite.h",
+      "trace_to_file.cc",
+      "trace_to_file.h",
+    ]
+    public_deps -= [ "//base:i18n" ]
+    deps -= [
+      "//third_party/icu:icuuc",
+      "//third_party/libxml",
+    ]
+  }
+}
+
+config("perf_test_config") {
+  defines = [ "PERF_TEST" ]
+}
+
+# This is a source set instead of a static library because it seems like some
+# linkers get confused when "main" is in a static library, and if you link to
+# this, you always want the object file anyway.
+source_set("test_support_perf") {
+  testonly = true
+  sources = [
+    "run_all_perftests.cc",
+  ]
+  deps = [
+    ":test_support",
+    "//base",
+    "//testing/gtest",
+  ]
+
+  public_configs = [ ":perf_test_config" ]
+}
+
+static_library("test_launcher_nacl_nonsfi") {
+  testonly = true
+  sources = [
+    "launcher/test_launcher_nacl_nonsfi.cc",
+    "launcher/test_launcher_nacl_nonsfi.h",
+  ]
+  deps = [
+    ":test_support",
+  ]
+}
+
+static_library("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",
+      "//build/config/sanitizers:deps",
+    ]
+  }
+}
+
+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/libchrome/base/test/DEPS b/libchrome/base/test/DEPS
new file mode 100644
index 0000000..5827c26
--- /dev/null
+++ b/libchrome/base/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/libxml",
+]
diff --git a/libchrome/base/test/OWNERS b/libchrome/base/test/OWNERS
new file mode 100644
index 0000000..92ecc88
--- /dev/null
+++ b/libchrome/base/test/OWNERS
@@ -0,0 +1 @@
+phajdan.jr@chromium.org
diff --git a/libchrome/base/test/data/file_util/binary_file.bin b/libchrome/base/test/data/file_util/binary_file.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/libchrome/base/test/data/file_util/binary_file.bin
Binary files differ
diff --git a/libchrome/base/test/data/file_util/binary_file_diff.bin b/libchrome/base/test/data/file_util/binary_file_diff.bin
new file mode 100644
index 0000000..103b26d
--- /dev/null
+++ b/libchrome/base/test/data/file_util/binary_file_diff.bin
Binary files differ
diff --git a/libchrome/base/test/data/file_util/binary_file_same.bin b/libchrome/base/test/data/file_util/binary_file_same.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/libchrome/base/test/data/file_util/binary_file_same.bin
Binary files differ
diff --git a/libchrome/base/test/data/file_util/blank_line.txt b/libchrome/base/test/data/file_util/blank_line.txt
new file mode 100644
index 0000000..8892069
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/file_util/blank_line_crlf.txt b/libchrome/base/test/data/file_util/blank_line_crlf.txt
new file mode 100644
index 0000000..3aefe52
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/file_util/crlf.txt b/libchrome/base/test/data/file_util/crlf.txt
new file mode 100644
index 0000000..0e62728
--- /dev/null
+++ b/libchrome/base/test/data/file_util/crlf.txt
@@ -0,0 +1 @@
+This file is the same.

diff --git a/libchrome/base/test/data/file_util/different.txt b/libchrome/base/test/data/file_util/different.txt
new file mode 100644
index 0000000..5b9f9c4
--- /dev/null
+++ b/libchrome/base/test/data/file_util/different.txt
@@ -0,0 +1 @@
+This file is different.
diff --git a/libchrome/base/test/data/file_util/different_first.txt b/libchrome/base/test/data/file_util/different_first.txt
new file mode 100644
index 0000000..8661d66
--- /dev/null
+++ b/libchrome/base/test/data/file_util/different_first.txt
@@ -0,0 +1 @@
+this file is the same.
diff --git a/libchrome/base/test/data/file_util/different_last.txt b/libchrome/base/test/data/file_util/different_last.txt
new file mode 100644
index 0000000..e8b3e5a
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/file_util/empty1.txt b/libchrome/base/test/data/file_util/empty1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libchrome/base/test/data/file_util/empty1.txt
diff --git a/libchrome/base/test/data/file_util/empty2.txt b/libchrome/base/test/data/file_util/empty2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libchrome/base/test/data/file_util/empty2.txt
diff --git a/libchrome/base/test/data/file_util/first1.txt b/libchrome/base/test/data/file_util/first1.txt
new file mode 100644
index 0000000..2c6e300
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/file_util/first2.txt b/libchrome/base/test/data/file_util/first2.txt
new file mode 100644
index 0000000..e39b5ec
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/file_util/original.txt b/libchrome/base/test/data/file_util/original.txt
new file mode 100644
index 0000000..4422f57
--- /dev/null
+++ b/libchrome/base/test/data/file_util/original.txt
@@ -0,0 +1 @@
+This file is the same.
diff --git a/libchrome/base/test/data/file_util/red.png b/libchrome/base/test/data/file_util/red.png
new file mode 100644
index 0000000..0806141
--- /dev/null
+++ b/libchrome/base/test/data/file_util/red.png
Binary files differ
diff --git a/libchrome/base/test/data/file_util/same.txt b/libchrome/base/test/data/file_util/same.txt
new file mode 100644
index 0000000..4422f57
--- /dev/null
+++ b/libchrome/base/test/data/file_util/same.txt
@@ -0,0 +1 @@
+This file is the same.
diff --git a/libchrome/base/test/data/file_util/same_length.txt b/libchrome/base/test/data/file_util/same_length.txt
new file mode 100644
index 0000000..157405c
--- /dev/null
+++ b/libchrome/base/test/data/file_util/same_length.txt
@@ -0,0 +1 @@
+This file is not same.
diff --git a/libchrome/base/test/data/file_util/shortened.txt b/libchrome/base/test/data/file_util/shortened.txt
new file mode 100644
index 0000000..2bee82c
--- /dev/null
+++ b/libchrome/base/test/data/file_util/shortened.txt
@@ -0,0 +1 @@
+This file is the
\ No newline at end of file
diff --git a/libchrome/base/test/data/file_version_info_unittest/FileVersionInfoTest1.dll b/libchrome/base/test/data/file_version_info_unittest/FileVersionInfoTest1.dll
new file mode 100755
index 0000000..bdf8dc0
--- /dev/null
+++ b/libchrome/base/test/data/file_version_info_unittest/FileVersionInfoTest1.dll
Binary files differ
diff --git a/libchrome/base/test/data/file_version_info_unittest/FileVersionInfoTest2.dll b/libchrome/base/test/data/file_version_info_unittest/FileVersionInfoTest2.dll
new file mode 100755
index 0000000..51e7966
--- /dev/null
+++ b/libchrome/base/test/data/file_version_info_unittest/FileVersionInfoTest2.dll
Binary files differ
diff --git a/libchrome/base/test/data/json/bom_feff.json b/libchrome/base/test/data/json/bom_feff.json
new file mode 100644
index 0000000..b05ae50
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/pe_image/pe_image_test_32.dll b/libchrome/base/test/data/pe_image/pe_image_test_32.dll
new file mode 100755
index 0000000..539d631
--- /dev/null
+++ b/libchrome/base/test/data/pe_image/pe_image_test_32.dll
Binary files differ
diff --git a/libchrome/base/test/data/pe_image/pe_image_test_64.dll b/libchrome/base/test/data/pe_image/pe_image_test_64.dll
new file mode 100755
index 0000000..8801e23
--- /dev/null
+++ b/libchrome/base/test/data/pe_image/pe_image_test_64.dll
Binary files differ
diff --git a/libchrome/base/test/data/serializer_nested_test.json b/libchrome/base/test/data/serializer_nested_test.json
new file mode 100644
index 0000000..cfea8e8
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/serializer_test.json b/libchrome/base/test/data/serializer_test.json
new file mode 100644
index 0000000..446925e
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/data/serializer_test_nowhitespace.json b/libchrome/base/test/data/serializer_test_nowhitespace.json
new file mode 100644
index 0000000..a1afdc5
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/ios/OWNERS b/libchrome/base/test/ios/OWNERS
new file mode 100644
index 0000000..40a68c7
--- /dev/null
+++ b/libchrome/base/test/ios/OWNERS
@@ -0,0 +1 @@
+rohitrao@chromium.org
diff --git a/libchrome/base/test/multiprocess_test.cc b/libchrome/base/test/multiprocess_test.cc
new file mode 100644
index 0000000..de56e7f
--- /dev/null
+++ b/libchrome/base/test/multiprocess_test.cc
@@ -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.
+
+#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"
+#include "build/build_config.h"
+
+namespace base {
+
+#if !defined(OS_ANDROID) && !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+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  // !OS_ANDROID && !__ANDROID__ && !__ANDROID_HOST__
+
+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/libchrome/base/test/multiprocess_test.h b/libchrome/base/test/multiprocess_test.h
new file mode 100644
index 0000000..ae4c3eb
--- /dev/null
+++ b/libchrome/base/test/multiprocess_test.h
@@ -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.
+
+#ifndef BASE_TEST_MULTIPROCESS_TEST_H_
+#define BASE_TEST_MULTIPROCESS_TEST_H_
+
+#include <string>
+
+#include "base/macros.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();
+
+#if defined(OS_ANDROID)
+
+// Enable the alternate test child implementation which support spawning a child
+// after threads have been created. If used, this MUST be the first line of
+// main(). The main function is passed in to avoid a link-time dependency in
+// component builds.
+void InitAndroidMultiProcessTestHelper(int (*main)(int, char**));
+
+// Returns true if the current process is a test child.
+bool AndroidIsChildProcess();
+
+// Wait for a test child to exit if the alternate test child implementation is
+// being used.
+bool AndroidWaitForChildExitWithTimeout(
+    const Process& process, TimeDelta timeout, int* exit_code)
+    WARN_UNUSED_RESULT;
+
+#endif  // defined(OS_ANDROID)
+
+// 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/libchrome/base/test/multiprocess_test_android.cc b/libchrome/base/test/multiprocess_test_android.cc
new file mode 100644
index 0000000..f58b452
--- /dev/null
+++ b/libchrome/base/test/multiprocess_test_android.cc
@@ -0,0 +1,454 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/containers/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/pickle.h"
+#include "base/posix/global_descriptors.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+namespace {
+
+const int kMaxMessageSize = 1024 * 1024;
+const int kFragmentSize = 4096;
+
+// Message sent between parent process and helper child process.
+enum class MessageType : uint32_t {
+  START_REQUEST,
+  START_RESPONSE,
+  WAIT_REQUEST,
+  WAIT_RESPONSE,
+};
+
+struct MessageHeader {
+  uint32_t size;
+  MessageType type;
+};
+
+struct StartProcessRequest {
+  MessageHeader header =
+      {sizeof(StartProcessRequest), MessageType::START_REQUEST};
+
+  uint32_t num_args = 0;
+  uint32_t num_fds = 0;
+};
+
+struct StartProcessResponse {
+  MessageHeader header =
+      {sizeof(StartProcessResponse), MessageType::START_RESPONSE};
+
+  pid_t child_pid;
+};
+
+struct WaitProcessRequest {
+  MessageHeader header =
+      {sizeof(WaitProcessRequest), MessageType::WAIT_REQUEST};
+
+  pid_t pid;
+  uint64_t timeout_ms;
+};
+
+struct WaitProcessResponse {
+  MessageHeader header =
+      {sizeof(WaitProcessResponse), MessageType::WAIT_RESPONSE};
+
+  bool success = false;
+  int32_t exit_code = 0;
+};
+
+// Helper class that implements an alternate test child launcher for
+// multi-process tests. The default implementation doesn't work if the child is
+// launched after starting threads. However, for some tests (i.e. Mojo), this
+// is necessary. This implementation works around that issue by forking a helper
+// process very early in main(), before any real work is done. Then, when a
+// child needs to be spawned, a message is sent to that helper process, which
+// then forks and returns the result to the parent. The forked child then calls
+// main() and things look as though a brand new process has been fork/exec'd.
+class LaunchHelper {
+ public:
+  using MainFunction = int (*)(int, char**);
+
+  LaunchHelper() {}
+
+  // Initialise the alternate test child implementation.
+  void Init(MainFunction main);
+
+  // Starts a child test helper process.
+  Process StartChildTestHelper(const std::string& procname,
+                               const CommandLine& base_command_line,
+                               const LaunchOptions& options);
+
+  // Waits for a child test helper process.
+  bool WaitForChildExitWithTimeout(const Process& process, TimeDelta timeout,
+                                   int* exit_code);
+
+  bool IsReady() const { return child_fd_ != -1; }
+  bool IsChild() const { return is_child_; }
+
+ private:
+  // Wrappers around sendmsg/recvmsg that supports message fragmentation.
+  void Send(int fd, const MessageHeader* msg, const std::vector<int>& fds);
+  ssize_t Recv(int fd, void* buf, std::vector<ScopedFD>* fds);
+
+  // Parent process implementation.
+  void DoParent(int fd);
+  // Helper process implementation.
+  void DoHelper(int fd);
+
+  void StartProcessInHelper(const StartProcessRequest* request,
+                           std::vector<ScopedFD> fds);
+  void WaitForChildInHelper(const WaitProcessRequest* request);
+
+  bool is_child_ = false;
+
+  // Parent vars.
+  int child_fd_ = -1;
+
+  // Helper vars.
+  int parent_fd_ = -1;
+  MainFunction main_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(LaunchHelper);
+};
+
+void LaunchHelper::Init(MainFunction main) {
+  main_ = main;
+
+  // Create a communication channel between the parent and child launch helper.
+  // fd[0] belongs to the parent, fd[1] belongs to the child.
+  int fds[2] = {-1, -1};
+  int rv = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds);
+  PCHECK(rv == 0);
+  CHECK_NE(-1, fds[0]);
+  CHECK_NE(-1, fds[1]);
+
+  pid_t pid = fork();
+  PCHECK(pid >= 0) << "Fork failed";
+  if (pid) {
+    // Parent.
+    rv = close(fds[1]);
+    PCHECK(rv == 0);
+    DoParent(fds[0]);
+  } else {
+    // Helper.
+    rv = close(fds[0]);
+    PCHECK(rv == 0);
+    DoHelper(fds[1]);
+    NOTREACHED();
+    _exit(0);
+  }
+}
+
+void LaunchHelper::Send(
+    int fd, const MessageHeader* msg, const std::vector<int>& fds) {
+  uint32_t bytes_remaining = msg->size;
+  const char* buf = reinterpret_cast<const char*>(msg);
+  while (bytes_remaining) {
+    size_t send_size =
+        (bytes_remaining > kFragmentSize) ? kFragmentSize : bytes_remaining;
+    bool success = UnixDomainSocket::SendMsg(
+        fd, buf, send_size,
+        (bytes_remaining == msg->size) ? fds : std::vector<int>());
+    CHECK(success);
+    bytes_remaining -= send_size;
+    buf += send_size;
+  }
+}
+
+ssize_t LaunchHelper::Recv(int fd, void* buf, std::vector<ScopedFD>* fds) {
+  ssize_t size = UnixDomainSocket::RecvMsg(fd, buf, kFragmentSize, fds);
+  if (size <= 0)
+    return size;
+
+  const MessageHeader* header = reinterpret_cast<const MessageHeader*>(buf);
+  CHECK(header->size < kMaxMessageSize);
+  uint32_t bytes_remaining = header->size - size;
+  char* buffer = reinterpret_cast<char*>(buf);
+  buffer += size;
+  while (bytes_remaining) {
+    std::vector<ScopedFD> dummy_fds;
+    size = UnixDomainSocket::RecvMsg(fd, buffer, kFragmentSize, &dummy_fds);
+    if (size <= 0)
+      return size;
+
+    CHECK(dummy_fds.empty());
+    CHECK(size == kFragmentSize ||
+          static_cast<size_t>(size) == bytes_remaining);
+    bytes_remaining -= size;
+    buffer += size;
+  }
+  return header->size;
+}
+
+void LaunchHelper::DoParent(int fd) {
+  child_fd_ = fd;
+}
+
+void LaunchHelper::DoHelper(int fd) {
+  parent_fd_ = fd;
+  is_child_ = true;
+  std::unique_ptr<char[]> buf(new char[kMaxMessageSize]);
+  while (true) {
+    // Wait for a message from the parent.
+    std::vector<ScopedFD> fds;
+    ssize_t size = Recv(parent_fd_, buf.get(), &fds);
+    if (size == 0 || (size < 0 && errno == ECONNRESET)) {
+      _exit(0);
+    }
+    PCHECK(size > 0);
+
+    const MessageHeader* header =
+        reinterpret_cast<const MessageHeader*>(buf.get());
+    CHECK_EQ(static_cast<ssize_t>(header->size), size);
+    switch (header->type) {
+      case MessageType::START_REQUEST:
+        StartProcessInHelper(
+            reinterpret_cast<const StartProcessRequest*>(buf.get()),
+            std::move(fds));
+        break;
+      case MessageType::WAIT_REQUEST:
+        WaitForChildInHelper(
+            reinterpret_cast<const WaitProcessRequest*>(buf.get()));
+        break;
+      default:
+        LOG(FATAL) << "Unsupported message type: "
+                   << static_cast<uint32_t>(header->type);
+    }
+  }
+}
+
+void LaunchHelper::StartProcessInHelper(const StartProcessRequest* request,
+                                        std::vector<ScopedFD> fds) {
+  pid_t pid = fork();
+  PCHECK(pid >= 0) << "Fork failed";
+  if (pid) {
+    // Helper.
+    StartProcessResponse resp;
+    resp.child_pid = pid;
+    Send(parent_fd_, reinterpret_cast<const MessageHeader*>(&resp),
+         std::vector<int>());
+  } else {
+    // Child.
+    PCHECK(close(parent_fd_) == 0);
+    parent_fd_ = -1;
+    CommandLine::Reset();
+
+    Pickle serialised_extra(reinterpret_cast<const char*>(request + 1),
+                            request->header.size - sizeof(StartProcessRequest));
+    PickleIterator iter(serialised_extra);
+    std::vector<std::string> args;
+    for (size_t i = 0; i < request->num_args; i++) {
+      std::string arg;
+      CHECK(iter.ReadString(&arg));
+      args.push_back(std::move(arg));
+    }
+
+    CHECK_EQ(request->num_fds, fds.size());
+    for (size_t i = 0; i < request->num_fds; i++) {
+      int new_fd;
+      CHECK(iter.ReadInt(&new_fd));
+      int old_fd = fds[i].release();
+      if (new_fd != old_fd) {
+        if (dup2(old_fd, new_fd) < 0) {
+          PLOG(FATAL) << "dup2";
+        }
+        PCHECK(close(old_fd) == 0);
+      }
+    }
+
+    // argv has argc+1 elements, where the last element is NULL.
+    std::unique_ptr<char*[]> argv(new char*[args.size() + 1]);
+    for (size_t i = 0; i < args.size(); i++) {
+      argv[i] = const_cast<char*>(args[i].c_str());
+    }
+    argv[args.size()] = nullptr;
+    _exit(main_(args.size(), argv.get()));
+    NOTREACHED();
+  }
+}
+
+void LaunchHelper::WaitForChildInHelper(const WaitProcessRequest* request) {
+  Process process(request->pid);
+  TimeDelta timeout = TimeDelta::FromMilliseconds(request->timeout_ms);
+  int exit_code = -1;
+  bool success = process.WaitForExitWithTimeout(timeout, &exit_code);
+
+  WaitProcessResponse resp;
+  resp.exit_code = exit_code;
+  resp.success = success;
+  Send(parent_fd_, reinterpret_cast<const MessageHeader*>(&resp),
+       std::vector<int>());
+}
+
+Process LaunchHelper::StartChildTestHelper(const std::string& procname,
+                                           const CommandLine& base_command_line,
+                                           const LaunchOptions& options) {
+
+  CommandLine command_line(base_command_line);
+  if (!command_line.HasSwitch(switches::kTestChildProcess))
+    command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+
+  StartProcessRequest request;
+  Pickle serialised_extra;
+  const CommandLine::StringVector& argv = command_line.argv();
+  for (const auto& arg : argv)
+    CHECK(serialised_extra.WriteString(arg));
+  request.num_args = argv.size();
+
+  std::vector<int> fds_to_send;
+  if (options.fds_to_remap) {
+    for (auto p : *options.fds_to_remap) {
+      CHECK(serialised_extra.WriteInt(p.second));
+      fds_to_send.push_back(p.first);
+    }
+    request.num_fds = options.fds_to_remap->size();
+  }
+
+  size_t buf_size = sizeof(StartProcessRequest) + serialised_extra.size();
+  request.header.size = buf_size;
+  std::unique_ptr<char[]> buffer(new char[buf_size]);
+  memcpy(buffer.get(), &request, sizeof(StartProcessRequest));
+  memcpy(buffer.get() + sizeof(StartProcessRequest), serialised_extra.data(),
+         serialised_extra.size());
+
+  // Send start message.
+  Send(child_fd_, reinterpret_cast<const MessageHeader*>(buffer.get()),
+       fds_to_send);
+
+  // Synchronously get response.
+  StartProcessResponse response;
+  std::vector<ScopedFD> recv_fds;
+  ssize_t resp_size = Recv(child_fd_, &response, &recv_fds);
+  PCHECK(resp_size == sizeof(StartProcessResponse));
+
+  return Process(response.child_pid);
+}
+
+bool LaunchHelper::WaitForChildExitWithTimeout(
+    const Process& process, TimeDelta timeout, int* exit_code) {
+
+  WaitProcessRequest request;
+  request.pid = process.Handle();
+  request.timeout_ms = timeout.InMilliseconds();
+
+  Send(child_fd_, reinterpret_cast<const MessageHeader*>(&request),
+       std::vector<int>());
+
+  WaitProcessResponse response;
+  std::vector<ScopedFD> recv_fds;
+  ssize_t resp_size = Recv(child_fd_, &response, &recv_fds);
+  PCHECK(resp_size == sizeof(WaitProcessResponse));
+
+  if (!response.success)
+    return false;
+
+  *exit_code = response.exit_code;
+  return true;
+}
+
+LazyInstance<LaunchHelper>::Leaky g_launch_helper;
+
+}  // namespace
+
+void InitAndroidMultiProcessTestHelper(int (*main)(int, char**)) {
+  DCHECK(main);
+  // Don't allow child processes to themselves create new child processes.
+  if (g_launch_helper.Get().IsChild())
+    return;
+  g_launch_helper.Get().Init(main);
+}
+
+bool AndroidIsChildProcess() {
+  return g_launch_helper.Get().IsChild();
+}
+
+bool AndroidWaitForChildExitWithTimeout(
+    const Process& process, TimeDelta timeout, int* exit_code) {
+  CHECK(g_launch_helper.Get().IsReady());
+  return g_launch_helper.Get().WaitForChildExitWithTimeout(
+      process, timeout, exit_code);
+}
+
+// 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) {
+  if (g_launch_helper.Get().IsReady()) {
+    return g_launch_helper.Get().StartChildTestHelper(
+        procname, base_command_line, 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/libchrome/base/test/opaque_ref_counted.cc b/libchrome/base/test/opaque_ref_counted.cc
new file mode 100644
index 0000000..ed6c36f
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/opaque_ref_counted.h b/libchrome/base/test/opaque_ref_counted.h
new file mode 100644
index 0000000..faf6a65
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/scoped_locale.cc b/libchrome/base/test/scoped_locale.cc
new file mode 100644
index 0000000..35b3fbe
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/scoped_locale.h b/libchrome/base/test/scoped_locale.h
new file mode 100644
index 0000000..ef64e98
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/test/sequenced_worker_pool_owner.cc b/libchrome/base/test/sequenced_worker_pool_owner.cc
new file mode 100644
index 0000000..8781495
--- /dev/null
+++ b/libchrome/base/test/sequenced_worker_pool_owner.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/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_->Shutdown();
+  pool_ = NULL;
+
+  // Spin the current message loop until SWP destruction verified in OnDestruct.
+  exit_loop_.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,
+                                                     exit_loop_.QuitClosure());
+}
+
+}  // namespace base
diff --git a/libchrome/base/test/sequenced_worker_pool_owner.h b/libchrome/base/test/sequenced_worker_pool_owner.h
new file mode 100644
index 0000000..05fc750
--- /dev/null
+++ b/libchrome/base/test/sequenced_worker_pool_owner.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_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
+#define BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
+
+#include <stddef.h>
+
+#include <cstddef>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.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.
+//
+// This class calls Shutdown on the owned SequencedWorkerPool in the destructor.
+// Tests may themselves call Shutdown earlier to test shutdown behavior.
+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;
+
+  // Used to run the current thread's message loop until the
+  // SequencedWorkerPool's destruction has been verified.
+  base::RunLoop exit_loop_;
+  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/libchrome/base/test/simple_test_clock.cc b/libchrome/base/test/simple_test_clock.cc
new file mode 100644
index 0000000..a2bdc2a
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/simple_test_clock.h b/libchrome/base/test/simple_test_clock.h
new file mode 100644
index 0000000..a70f99c
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/simple_test_tick_clock.cc b/libchrome/base/test/simple_test_tick_clock.cc
new file mode 100644
index 0000000..c6375bd
--- /dev/null
+++ b/libchrome/base/test/simple_test_tick_clock.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/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;
+}
+
+void SimpleTestTickClock::SetNowTicks(TimeTicks ticks) {
+  AutoLock lock(lock_);
+  now_ticks_ = ticks;
+}
+
+}  // namespace base
diff --git a/libchrome/base/test/simple_test_tick_clock.h b/libchrome/base/test/simple_test_tick_clock.h
new file mode 100644
index 0000000..f2f7581
--- /dev/null
+++ b/libchrome/base/test/simple_test_tick_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_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);
+
+  // Sets the clock to the given time.
+  void SetNowTicks(TimeTicks ticks);
+
+ private:
+  // Protects |now_ticks_|.
+  Lock lock_;
+
+  TimeTicks now_ticks_;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
diff --git a/libchrome/base/test/test_file_util.cc b/libchrome/base/test/test_file_util.cc
new file mode 100644
index 0000000..40b25f0
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/test_file_util.h b/libchrome/base/test/test_file_util.h
new file mode 100644
index 0000000..7042e48
--- /dev/null
+++ b/libchrome/base/test/test_file_util.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_TEST_TEST_FILE_UTIL_H_
+#define BASE_TEST_TEST_FILE_UTIL_H_
+
+// File utility functions used only by tests.
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include <jni.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/libchrome/base/test/test_file_util_linux.cc b/libchrome/base/test/test_file_util_linux.cc
new file mode 100644
index 0000000..0ef5c0a
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/test_file_util_posix.cc b/libchrome/base/test/test_file_util_posix.cc
new file mode 100644
index 0000000..b817283
--- /dev/null
+++ b/libchrome/base/test/test_file_util_posix.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/test/test_file_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.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"
+#include "build/build_config.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/libchrome/base/test/test_io_thread.cc b/libchrome/base/test/test_io_thread.cc
new file mode 100644
index 0000000..1fa0412
--- /dev/null
+++ b/libchrome/base/test/test_io_thread.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/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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                            WaitableEvent::InitialState::NOT_SIGNALED);
+  task_runner()->PostTask(from_here,
+                          base::Bind(&PostTaskAndWaitHelper, &event, task));
+  event.Wait();
+}
+
+}  // namespace base
diff --git a/libchrome/base/test/test_io_thread.h b/libchrome/base/test/test_io_thread.h
new file mode 100644
index 0000000..c2ed187
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/test_pending_task.cc b/libchrome/base/test/test_pending_task.cc
new file mode 100644
index 0000000..87b107e
--- /dev/null
+++ b/libchrome/base/test/test_pending_task.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 <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) {}
+
+TestPendingTask::TestPendingTask(const TestPendingTask& other) = default;
+
+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());
+}
+
+std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+TestPendingTask::AsValue() const {
+  std::unique_ptr<base::trace_event::TracedValue> state(
+      new base::trace_event::TracedValue());
+  AsValueInto(state.get());
+  return std::move(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/libchrome/base/test/test_pending_task.h b/libchrome/base/test/test_pending_task.h
new file mode 100644
index 0000000..2dbdb7e
--- /dev/null
+++ b/libchrome/base/test/test_pending_task.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_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 TestPendingTask& other);
+  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;
+  std::unique_ptr<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/libchrome/base/test/test_simple_task_runner.cc b/libchrome/base/test/test_simple_task_runner.cc
new file mode 100644
index 0000000..cc39fab
--- /dev/null
+++ b/libchrome/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/libchrome/base/test/test_simple_task_runner.h b/libchrome/base/test/test_simple_task_runner.h
new file mode 100644
index 0000000..338c634
--- /dev/null
+++ b/libchrome/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/compiler_specific.h"
+#include "base/macros.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/libchrome/base/test/test_switches.cc b/libchrome/base/test/test_switches.cc
new file mode 100644
index 0000000..817a38e
--- /dev/null
+++ b/libchrome/base/test/test_switches.cc
@@ -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.
+
+#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";
+
+// Force running all requested tests and retries even if too many test errors
+// occur.
+const char switches::kTestLauncherForceRunBrokenTests[] =
+    "test-launcher-force-run-broken-tests";
+
+// 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";
+
+// Path where to save a trace of test launcher's execution.
+const char switches::kTestLauncherTrace[] = "test-launcher-trace";
+
+// 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/libchrome/base/test/test_switches.h b/libchrome/base/test/test_switches.h
new file mode 100644
index 0000000..88ef0ce
--- /dev/null
+++ b/libchrome/base/test/test_switches.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_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 kTestLauncherForceRunBrokenTests[];
+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 kTestLauncherTrace[];
+extern const char kTestTinyTimeout[];
+extern const char kUiTestActionTimeout[];
+extern const char kUiTestActionMaxTimeout[];
+
+}  // namespace switches
+
+#endif  // BASE_TEST_TEST_SWITCHES_H_
diff --git a/libchrome/base/test/test_timeouts.cc b/libchrome/base/test/test_timeouts.cc
new file mode 100644
index 0000000..55e9a79
--- /dev/null
+++ b/libchrome/base/test/test_timeouts.cc
@@ -0,0 +1,114 @@
+// 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"
+#include "build/build_config.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/libchrome/base/test/test_timeouts.h b/libchrome/base/test/test_timeouts.h
new file mode 100644
index 0000000..ddaf05b
--- /dev/null
+++ b/libchrome/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/logging.h"
+#include "base/macros.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/libchrome/base/test/trace_event_analyzer.cc b/libchrome/base/test/trace_event_analyzer.cc
new file mode 100644
index 0000000..64436dc
--- /dev/null
+++ b/libchrome/base/test/trace_event_analyzer.cc
@@ -0,0 +1,999 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <math.h>
+
+#include <algorithm>
+#include <memory>
+#include <set>
+
+#include "base/json/json_reader.h"
+#include "base/strings/pattern.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(TraceEvent&& other) = default;
+
+TraceEvent::~TraceEvent() {
+}
+
+TraceEvent& TraceEvent::operator=(TraceEvent&& rhs) = default;
+
+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_MEMORY_DUMP ||
+                     phase == TRACE_EVENT_PHASE_ENTER_CONTEXT ||
+                     phase == TRACE_EVENT_PHASE_LEAVE_CONTEXT ||
+                     phase == TRACE_EVENT_PHASE_CREATE_OBJECT ||
+                     phase == TRACE_EVENT_PHASE_DELETE_OBJECT ||
+                     phase == TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ||
+                     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;
+    }
+    // Record all arguments as values.
+    arg_values[it.key()] = it.value().CreateDeepCopy();
+  }
+
+  return true;
+}
+
+double TraceEvent::GetAbsTimeToOtherEvent() const {
+  return fabs(other_event->timestamp - timestamp);
+}
+
+bool TraceEvent::GetArgAsString(const std::string& name,
+                                std::string* arg) const {
+  const auto it = arg_strings.find(name);
+  if (it != arg_strings.end()) {
+    *arg = it->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::GetArgAsNumber(const std::string& name,
+                                double* arg) const {
+  const auto it = arg_numbers.find(name);
+  if (it != arg_numbers.end()) {
+    *arg = it->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::GetArgAsValue(const std::string& name,
+                               std::unique_ptr<base::Value>* arg) const {
+  const auto it = arg_values.find(name);
+  if (it != arg_values.end()) {
+    *arg = it->second->CreateDeepCopy();
+    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());
+}
+
+bool TraceEvent::HasArg(const std::string& name) const {
+  return (arg_values.find(name) != arg_values.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);
+}
+
+std::unique_ptr<base::Value> TraceEvent::GetKnownArgAsValue(
+    const std::string& name) const {
+  std::unique_ptr<base::Value> arg_value;
+  bool result = GetArgAsValue(name, &arg_value);
+  DCHECK(result);
+  return arg_value;
+}
+
+// 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_t num) {
+  return Query(static_cast<double>(num));
+}
+
+Query Query::Uint(uint32_t 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 = base::MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = base::MatchPattern(rhs, lhs);
+      else
+        *result = (lhs == rhs);
+      return true;
+    case OP_NE:
+      if (right().is_pattern_)
+        *result = !base::MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = !base::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_t>(lhs) %
+                                 static_cast<int64_t>(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) {
+  std::unique_ptr<base::Value> root = base::JSONReader::Read(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(std::move(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) {
+  std::unique_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/libchrome/base/test/trace_event_analyzer.h b/libchrome/base/test/trace_event_analyzer.h
new file mode 100644
index 0000000..0e2366b
--- /dev/null
+++ b/libchrome/base/test/trace_event_analyzer.h
@@ -0,0 +1,715 @@
+// Copyright (c) 2012 The Chromium 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 <stddef.h>
+#include <stdint.h>
+
+#include <map>
+
+#include "base/macros.h"
+#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(TraceEvent&& other);
+  ~TraceEvent();
+
+  bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
+
+  bool operator< (const TraceEvent& rhs) const {
+    return timestamp < rhs.timestamp;
+  }
+
+  TraceEvent& operator=(TraceEvent&& rhs);
+
+  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;
+  // Return the argument value if it exists.
+  bool GetArgAsValue(const std::string& name,
+                     std::unique_ptr<base::Value>* 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;
+  // Check if argument exists.
+  bool HasArg(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;
+  std::unique_ptr<base::Value> GetKnownArgAsValue(
+      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;
+  std::map<std::string, std::unique_ptr<base::Value>> arg_values;
+
+  // 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_t num);
+  static Query Uint(uint32_t 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_t args (doubles are casted to int64_t 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/libchrome/base/test/trace_event_analyzer_unittest.cc b/libchrome/base/test/trace_event_analyzer_unittest.cc
new file mode 100644
index 0000000..086cfc9
--- /dev/null
+++ b/libchrome/base/test/trace_event_analyzer_unittest.cc
@@ -0,0 +1,955 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <stdint.h>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_event_argument.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(
+      base::WaitableEvent::ResetPolicy::AUTOMATIC,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  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();
+
+  std::unique_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;
+  event.arg_values["dict"] = WrapUnique(new base::DictionaryValue());
+
+  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"));
+  ASSERT_TRUE(event.HasArg("dict"));
+  ASSERT_FALSE(event.HasArg("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());
+
+  std::unique_ptr<base::Value> arg;
+  EXPECT_TRUE(event.GetArgAsValue("dict", &arg));
+  EXPECT_EQ(base::Value::TYPE_DICTIONARY, arg->GetType());
+}
+
+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();
+
+  std::unique_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();
+
+  std::unique_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();
+
+  std::unique_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_t 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();
+
+  std::unique_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_t 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();
+
+  std::unique_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();
+
+  std::unique_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();
+
+  std::unique_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();
+
+  std::unique_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();
+
+  std::unique_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();
+
+  std::unique_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;
+  double 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) {
+    timestamp += little_delta;
+    TraceEvent event;
+    event.timestamp = timestamp;
+    events.push_back(std::move(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.
+  {
+    timestamp += big_delta;
+    TraceEvent event;
+    event.timestamp = timestamp;
+    events.push_back(std::move(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.
+  {
+    timestamp += tiny_delta;
+    TraceEvent event;
+    event.timestamp = timestamp;
+    events.push_back(std::move(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.
+  {
+    TraceEvent event;
+    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));
+}
+
+TEST_F(TraceEventAnalyzerTest, ComplexArgument) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    std::unique_ptr<base::trace_event::TracedValue> value(
+        new base::trace_event::TracedValue);
+    value->SetString("property", "value");
+    TRACE_EVENT1("cat", "name", "arg", std::move(value));
+  }
+  EndTracing();
+
+  std::unique_ptr<TraceAnalyzer> analyzer(
+      TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  TraceEventVector events;
+  analyzer->FindEvents(Query::EventName() == Query::String("name"), &events);
+
+  EXPECT_EQ(1u, events.size());
+  EXPECT_EQ("cat", events[0]->category);
+  EXPECT_EQ("name", events[0]->name);
+  EXPECT_TRUE(events[0]->HasArg("arg"));
+
+  std::unique_ptr<base::Value> arg;
+  events[0]->GetArgAsValue("arg", &arg);
+  base::DictionaryValue* arg_dict;
+  EXPECT_TRUE(arg->GetAsDictionary(&arg_dict));
+  std::string property;
+  EXPECT_TRUE(arg_dict->GetString("property", &property));
+  EXPECT_EQ("value", property);
+}
+
+}  // namespace trace_analyzer
diff --git a/libchrome/base/third_party/dynamic_annotations/dynamic_annotations.h b/libchrome/base/third_party/dynamic_annotations/dynamic_annotations.h
new file mode 100644
index 0000000..8d7f052
--- /dev/null
+++ b/libchrome/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/libchrome/base/third_party/icu/LICENSE b/libchrome/base/third_party/icu/LICENSE
new file mode 100644
index 0000000..40282f4
--- /dev/null
+++ b/libchrome/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/libchrome/base/third_party/icu/README.chromium b/libchrome/base/third_party/icu/README.chromium
new file mode 100644
index 0000000..6a9a15a
--- /dev/null
+++ b/libchrome/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/libchrome/base/third_party/icu/icu_utf.cc b/libchrome/base/third_party/icu/icu_utf.cc
new file mode 100644
index 0000000..2b67c5d
--- /dev/null
+++ b/libchrome/base/third_party/icu/icu_utf.cc
@@ -0,0 +1,227 @@
+/*
+******************************************************************************
+*
+*   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_t 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_t* s,
+                              int32_t* pi,
+                              int32_t length,
+                              UChar32 c,
+                              UBool strict) {
+  int32_t i = *pi;
+  uint8_t count = CBU8_COUNT_TRAIL_BYTES(c);
+    if((i)+count<=(length)) {
+      uint8_t 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_t 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_t 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/libchrome/base/third_party/icu/icu_utf.h b/libchrome/base/third_party/icu/icu_utf.h
new file mode 100644
index 0000000..4370fde
--- /dev/null
+++ b/libchrome/base/third_party/icu/icu_utf.h
@@ -0,0 +1,400 @@
+/*
+*******************************************************************************
+*
+*   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 <stdint.h>
+
+namespace base_icu {
+
+typedef int32_t UChar32;
+typedef uint16_t UChar;
+typedef int8_t 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_t)(c) <= 0xfdef || ((c)&0xfffe) == 0xfffe) && \
+   (uint32_t)(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_t)(c) < 0xd800 ||                               \
+   ((uint32_t)(c) > 0xdfff && (uint32_t)(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_t 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_t)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_t)((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_t)(c) <= 0x7f                                                    \
+       ? 1                                                                  \
+       : ((uint32_t)(c) <= 0x7ff                                            \
+              ? 2                                                           \
+              : ((uint32_t)(c) <= 0xd7ff                                    \
+                     ? 3                                                    \
+                     : ((uint32_t)(c) <= 0xdfff || (uint32_t)(c) > 0x10ffff \
+                            ? 0                                             \
+                            : ((uint32_t)(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_t* s,
+                              int32_t* pi,
+                              int32_t 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_t * 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_t)(c)) >= 0x80) {                                        \
+      if (CBU8_IS_LEAD(c)) {                                             \
+        (c) = base_icu::utf8_nextCharSafeBody((const uint8_t*)s, &(i),   \
+                                              (int32_t)(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_t * 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_t)(c) <= 0x7f) {                               \
+      (s)[(i)++] = (uint8_t)(c);                               \
+    } else {                                                   \
+      if ((uint32_t)(c) <= 0x7ff) {                            \
+        (s)[(i)++] = (uint8_t)(((c) >> 6) | 0xc0);             \
+      } else {                                                 \
+        if ((uint32_t)(c) <= 0xffff) {                         \
+          (s)[(i)++] = (uint8_t)(((c) >> 12) | 0xe0);          \
+        } else {                                               \
+          (s)[(i)++] = (uint8_t)(((c) >> 18) | 0xf0);          \
+          (s)[(i)++] = (uint8_t)((((c) >> 12) & 0x3f) | 0x80); \
+        }                                                      \
+        (s)[(i)++] = (uint8_t)((((c) >> 6) & 0x3f) | 0x80);    \
+      }                                                        \
+      (s)[(i)++] = (uint8_t)(((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_t)(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_t __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_t)(c) <= 0xffff) {                   \
+      (s)[(i)++] = (uint16_t)(c);                    \
+    } else {                                         \
+      (s)[(i)++] = (uint16_t)(((c) >> 10) + 0xd7c0); \
+      (s)[(i)++] = (uint16_t)(((c)&0x3ff) | 0xdc00); \
+    }                                                \
+  }
+
+}  // namesapce base_icu
+
+#endif  // BASE_THIRD_PARTY_ICU_ICU_UTF_H_
diff --git a/libchrome/base/third_party/libevent/event.h b/libchrome/base/third_party/libevent/event.h
new file mode 100644
index 0000000..d47d797
--- /dev/null
+++ b/libchrome/base/third_party/libevent/event.h
@@ -0,0 +1,10 @@
+// The Chromium build contains its own checkout of libevent. This stub is used
+// when building the Chrome OS or Android libchrome package to instead use the
+// system headers.
+#if defined(__ANDROID__) || defined(__ANDROID_HOST__)
+#include <event2/event.h>
+#include <event2/event_compat.h>
+#include <event2/event_struct.h>
+#else
+#include <event.h>
+#endif
diff --git a/libchrome/base/third_party/nspr/LICENSE b/libchrome/base/third_party/nspr/LICENSE
new file mode 100644
index 0000000..eba7b77
--- /dev/null
+++ b/libchrome/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/libchrome/base/third_party/nspr/OWNERS b/libchrome/base/third_party/nspr/OWNERS
new file mode 100644
index 0000000..20ba660
--- /dev/null
+++ b/libchrome/base/third_party/nspr/OWNERS
@@ -0,0 +1,2 @@
+rsleevi@chromium.org
+wtc@chromium.org
diff --git a/libchrome/base/third_party/nspr/README.chromium b/libchrome/base/third_party/nspr/README.chromium
new file mode 100644
index 0000000..3659a2c
--- /dev/null
+++ b/libchrome/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/libchrome/base/third_party/nspr/prtime.cc b/libchrome/base/third_party/nspr/prtime.cc
new file mode 100644
index 0000000..97d2c27
--- /dev/null
+++ b/libchrome/base/third_party/nspr/prtime.cc
@@ -0,0 +1,1186 @@
+/* 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
+ *   Upstream implementation from
+ *   http://lxr.mozilla.org/nspr/source/pr/src/misc/prtime.c#221
+ * 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 <limits.h>
+
+#include "base/logging.h"
+#include "base/third_party/nspr/prtime.h"
+#include "build/build_config.h"
+
+#include <errno.h>  /* for EINVAL */
+#include <time.h>
+
+/*
+ * 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))
+
+/* 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
+
+/*
+ * 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}
+};
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * 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)
+{
+  PRExplodedTime copy;
+  PRTime retVal;
+  PRInt64 secPerDay, usecPerSec;
+  PRInt64 temp;
+  PRInt64 numSecs64;
+  PRInt32 numDays;
+  PRInt32 numSecs;
+
+  /* Normalize first.  Do this on our copy */
+  copy = *exploded;
+  PR_NormalizeTime(&copy, PR_GMTParameters);
+
+  numDays = DAYS_BETWEEN_YEARS(1970, copy.tm_year);
+
+  numSecs = copy.tm_yday * 86400 + copy.tm_hour * 3600 + copy.tm_min * 60 +
+            copy.tm_sec;
+
+  LL_I2L(temp, numDays);
+  LL_I2L(secPerDay, 86400);
+  LL_MUL(temp, temp, secPerDay);
+  LL_I2L(numSecs64, numSecs);
+  LL_ADD(numSecs64, numSecs64, temp);
+
+  /* apply the GMT and DST offsets */
+  LL_I2L(temp, copy.tm_params.tp_gmt_offset);
+  LL_SUB(numSecs64, numSecs64, temp);
+  LL_I2L(temp, copy.tm_params.tp_dst_offset);
+  LL_SUB(numSecs64, numSecs64, temp);
+
+  LL_I2L(usecPerSec, 1000000L);
+  LL_MUL(temp, numSecs64, usecPerSec);
+  LL_I2L(retVal, copy.tm_usec);
+  LL_ADD(retVal, retVal, temp);
+
+  return retVal;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * 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/libchrome/base/third_party/nspr/prtime.h b/libchrome/base/third_party/nspr/prtime.h
new file mode 100644
index 0000000..20bae38
--- /dev/null
+++ b/libchrome/base/third_party/nspr/prtime.h
@@ -0,0 +1,263 @@
+/* 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
+
+/*
+ * Long-long (64-bit signed integer type) support macros used by
+ * PR_ImplodeTime().
+ * See http://lxr.mozilla.org/nspr/source/pr/include/prlong.h
+ */
+
+#define LL_I2L(l, i) ((l) = (PRInt64)(i))
+#define LL_MUL(r, a, b) ((r) = (a) * (b))
+#define LL_ADD(r, a, b) ((r) = (a) + (b))
+#define LL_SUB(r, a, b) ((r) = (a) - (b))
+
+/**********************************************************************/
+/************************* 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/libchrome/base/third_party/valgrind/memcheck.h b/libchrome/base/third_party/valgrind/memcheck.h
new file mode 100644
index 0000000..aac34fc
--- /dev/null
+++ b/libchrome/base/third_party/valgrind/memcheck.h
@@ -0,0 +1,282 @@
+#ifdef ANDROID
+  #include "memcheck/memcheck.h"
+#else
+/*
+   ----------------------------------------------------------------
+
+   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
+
+#endif
diff --git a/libchrome/base/third_party/valgrind/valgrind.h b/libchrome/base/third_party/valgrind/valgrind.h
new file mode 100644
index 0000000..0668a71
--- /dev/null
+++ b/libchrome/base/third_party/valgrind/valgrind.h
@@ -0,0 +1,4797 @@
+#ifdef ANDROID
+  #include "include/valgrind.h"
+#else
+/* -*- 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 */
+
+#endif
diff --git a/libchrome/base/threading/OWNERS b/libchrome/base/threading/OWNERS
new file mode 100644
index 0000000..4198e99
--- /dev/null
+++ b/libchrome/base/threading/OWNERS
@@ -0,0 +1,2 @@
+# For thread_resrictions.*
+jam@chromium.org
diff --git a/libchrome/base/threading/non_thread_safe.h b/libchrome/base/threading/non_thread_safe.h
new file mode 100644
index 0000000..d41c086
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/non_thread_safe_impl.cc b/libchrome/base/threading/non_thread_safe_impl.cc
new file mode 100644
index 0000000..7e729d9
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/non_thread_safe_impl.h b/libchrome/base/threading/non_thread_safe_impl.h
new file mode 100644
index 0000000..a3a356d
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/non_thread_safe_unittest.cc b/libchrome/base/threading/non_thread_safe_unittest.cc
new file mode 100644
index 0000000..d523fc5
--- /dev/null
+++ b/libchrome/base/threading/non_thread_safe_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2012 The Chromium Authors. All 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.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.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:
+  std::unique_ptr<NonThreadSafeClass> non_thread_safe_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
+};
+
+}  // namespace
+
+TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
+  std::unique_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) {
+  std::unique_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() {
+  std::unique_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() {
+  std::unique_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/libchrome/base/threading/platform_thread.h b/libchrome/base/threading/platform_thread.h
new file mode 100644
index 0000000..9b217a9
--- /dev/null
+++ b/libchrome/base/threading/platform_thread.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2012 The Chromium 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 <stddef.h>
+
+#include "base/base_export.h"
+#include "base/macros.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) {}
+
+  explicit PlatformThreadHandle(Handle handle) : handle_(handle) {}
+
+  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_;
+};
+
+const PlatformThreadId kInvalidThreadId(0);
+
+// Valid values for priority of Thread::Options and SimpleThread::Options, and
+// SetCurrentThreadPriority(), listed in increasing order of importance.
+enum class ThreadPriority : int {
+  // 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 will try to
+  // initialize the context for current thread unless it's a WorkerThread.
+  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) {
+    return CreateWithPriority(stack_size, delegate, thread_handle,
+                              ThreadPriority::NORMAL);
+  }
+
+  // CreateWithPriority() does the same thing as Create() except the priority of
+  // the thread is set based on |priority|.
+  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);
+
+  // Detaches and releases the thread handle. The thread is no longer joinable
+  // and |thread_handle| is invalidated after this call.
+  static void Detach(PlatformThreadHandle thread_handle);
+
+  // Toggles the current thread's priority at runtime. A thread may not be able
+  // to raise its priority back up after lowering it if the process does not
+  // have a proper permission, e.g. CAP_SYS_NICE on Linux. A thread may not be
+  // able to lower its priority back down after raising it to REALTIME_AUDIO.
+  // Since changing other threads' priority is not permitted in favor of
+  // security, this interface is restricted to change only the current thread
+  // priority (https://crbug.com/399473).
+  static void SetCurrentThreadPriority(ThreadPriority priority);
+
+  static ThreadPriority GetCurrentThreadPriority();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/libchrome/base/threading/platform_thread_internal_posix.cc b/libchrome/base/threading/platform_thread_internal_posix.cc
new file mode 100644
index 0000000..378a24d
--- /dev/null
+++ b/libchrome/base/threading/platform_thread_internal_posix.cc
@@ -0,0 +1,39 @@
+// 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/containers/adapters.h"
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+int ThreadPriorityToNiceValue(ThreadPriority priority) {
+  for (const auto& pair : kThreadPriorityToNiceValueMap) {
+    if (pair.priority == priority)
+      return pair.nice_value;
+  }
+  NOTREACHED() << "Unknown ThreadPriority";
+  return 0;
+}
+
+ThreadPriority NiceValueToThreadPriority(int nice_value) {
+  // Try to find a priority that best describes |nice_value|. If there isn't
+  // an exact match, this method returns the closest priority whose nice value
+  // is higher (lower priority) than |nice_value|.
+  for (const auto& pair : Reversed(kThreadPriorityToNiceValueMap)) {
+    if (pair.nice_value >= nice_value)
+      return pair.priority;
+  }
+
+  // Reaching here means |nice_value| is more than any of the defined
+  // priorities. The lowest priority is suitable in this case.
+  return ThreadPriority::BACKGROUND;
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/libchrome/base/threading/platform_thread_internal_posix.h b/libchrome/base/threading/platform_thread_internal_posix.h
new file mode 100644
index 0000000..5f4a215
--- /dev/null
+++ b/libchrome/base/threading/platform_thread_internal_posix.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_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+#define BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+
+#include "base/base_export.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace internal {
+
+struct ThreadPriorityToNiceValuePair {
+  ThreadPriority priority;
+  int nice_value;
+};
+// The elements must be listed in the order of increasing priority (lowest
+// priority first), that is, in the order of decreasing nice values (highest
+// nice value first).
+BASE_EXPORT 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.
+BASE_EXPORT ThreadPriority NiceValueToThreadPriority(int nice_value);
+
+// Allows platform specific tweaks to the generic POSIX solution for
+// SetCurrentThreadPriority. Returns true if the platform-specific
+// implementation handled this |priority| change, false if the generic
+// implementation should instead proceed.
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority);
+
+// Returns true if there is a platform-specific ThreadPriority set on the
+// current thread (and returns the actual ThreadPriority via |priority|).
+// Returns false otherwise, leaving |priority| untouched.
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority);
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
diff --git a/libchrome/base/threading/platform_thread_linux.cc b/libchrome/base/threading/platform_thread_linux.cc
new file mode 100644
index 0000000..ab7c97e
--- /dev/null
+++ b/libchrome/base/threading/platform_thread_linux.cc
@@ -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/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+#include <stddef.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 "build/build_config.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, -8},
+    {ThreadPriority::REALTIME_AUDIO, -10},
+};
+
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
+#if !defined(OS_NACL)
+  return priority == ThreadPriority::REALTIME_AUDIO &&
+         pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+  return false;
+#endif
+}
+
+bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
+#if !defined(OS_NACL)
+  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 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 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/libchrome/base/threading/platform_thread_mac.mm b/libchrome/base/threading/platform_thread_mac.mm
new file mode 100644
index 0000000..51f3621
--- /dev/null
+++ b/libchrome/base/threading/platform_thread_mac.mm
@@ -0,0 +1,247 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+#include <sys/resource.h>
+
+#include <algorithm>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+NSString* const kThreadPriorityKey = @"CrThreadPriorityKey";
+}  // namespace
+
+// 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::SetCurrentThreadPriority(ThreadPriority priority) {
+  // Convert from pthread_t to mach thread identifier.
+  mach_port_t mach_thread_id =
+      pthread_mach_thread_np(PlatformThread::CurrentHandle().platform_handle());
+
+  switch (priority) {
+    case ThreadPriority::NORMAL:
+    case ThreadPriority::BACKGROUND:
+    case ThreadPriority::DISPLAY:
+      // Add support for non-NORMAL thread priorities. https://crbug.com/554651
+      SetPriorityNormal(mach_thread_id);
+      break;
+    case ThreadPriority::REALTIME_AUDIO:
+      SetPriorityRealtimeAudio(mach_thread_id);
+      break;
+  }
+
+  [[[NSThread currentThread] threadDictionary]
+      setObject:@(static_cast<int>(priority))
+         forKey:kThreadPriorityKey];
+}
+
+// static
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
+  NSNumber* priority = base::mac::ObjCCast<NSNumber>([[[NSThread currentThread]
+      threadDictionary] objectForKey:kThreadPriorityKey]);
+
+  if (!priority)
+    return ThreadPriority::NORMAL;
+
+  ThreadPriority thread_priority =
+      static_cast<ThreadPriority>(priority.intValue);
+  switch (thread_priority) {
+    case ThreadPriority::BACKGROUND:
+    case ThreadPriority::NORMAL:
+    case ThreadPriority::DISPLAY:
+    case ThreadPriority::REALTIME_AUDIO:
+      return thread_priority;
+    default:
+      NOTREACHED() << "Unknown priority.";
+      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 TerminateOnThread() {
+}
+
+}  // namespace base
diff --git a/libchrome/base/threading/platform_thread_posix.cc b/libchrome/base/threading/platform_thread_posix.cc
new file mode 100644
index 0000000..2321b3c
--- /dev/null
+++ b/libchrome/base/threading/platform_thread_posix.cc
@@ -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.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include <memory>
+
+#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/threading/thread_restrictions.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <sys/syscall.h>
+#elif defined(OS_ANDROID)
+#include <sys/types.h>
+#endif
+
+namespace base {
+
+void InitThreading();
+void TerminateOnThread();
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
+
+namespace {
+
+struct ThreadParams {
+  ThreadParams()
+      : delegate(NULL), joinable(false), priority(ThreadPriority::NORMAL) {}
+
+  PlatformThread::Delegate* delegate;
+  bool joinable;
+  ThreadPriority priority;
+};
+
+void* ThreadFunc(void* params) {
+  PlatformThread::Delegate* delegate = nullptr;
+
+  {
+    std::unique_ptr<ThreadParams> thread_params(
+        static_cast<ThreadParams*>(params));
+
+    delegate = thread_params->delegate;
+    if (!thread_params->joinable)
+      base::ThreadRestrictions::SetSingletonAllowed(false);
+
+#if !defined(OS_NACL)
+    // Threads on linux/android may inherit their priority from the thread
+    // where they were created. This explicitly sets the priority of all new
+    // threads.
+    PlatformThread::SetCurrentThreadPriority(thread_params->priority);
+#endif
+  }
+
+  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) {
+  DCHECK(thread_handle);
+  base::InitThreading();
+
+  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);
+
+  std::unique_ptr<ThreadParams> params(new ThreadParams);
+  params->delegate = delegate;
+  params->joinable = joinable;
+  params->priority = priority;
+
+  pthread_t handle;
+  int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
+  bool success = !err;
+  if (success) {
+    // ThreadParams should be deleted on the created thread after used.
+    ignore_result(params.release());
+  } else {
+    // Value of |handle| is undefined if pthread_create fails.
+    handle = 0;
+    errno = err;
+    PLOG(ERROR) << "pthread_create";
+  }
+  *thread_handle = PlatformThreadHandle(handle);
+
+  pthread_attr_destroy(&attributes);
+
+  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_t>(pthread_self());
+#elif defined(OS_POSIX)
+  return reinterpret_cast<int64_t>(pthread_self());
+#endif
+}
+
+// static
+PlatformThreadRef PlatformThread::CurrentRef() {
+  return PlatformThreadRef(pthread_self());
+}
+
+// static
+PlatformThreadHandle PlatformThread::CurrentHandle() {
+  return PlatformThreadHandle(pthread_self());
+}
+
+// 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::CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                        PlatformThreadHandle* thread_handle,
+                                        ThreadPriority priority) {
+  return CreateThread(stack_size, true,  // joinable thread
+                      delegate, thread_handle, priority);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+  PlatformThreadHandle unused;
+
+  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));
+}
+
+// static
+void PlatformThread::Detach(PlatformThreadHandle thread_handle) {
+  CHECK_EQ(0, pthread_detach(thread_handle.platform_handle()));
+}
+
+// Mac has its own Set/GetCurrentThreadPriority() implementations.
+#if !defined(OS_MACOSX)
+
+// static
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();
+#else
+  if (internal::SetCurrentThreadPriorityForPlatform(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).
+  const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
+  if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
+    DVPLOG(1) << "Failed to set nice value of thread ("
+              << PlatformThread::CurrentId() << ") to " << nice_setting;
+  }
+#endif  // defined(OS_NACL)
+}
+
+// static
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();
+  return ThreadPriority::NORMAL;
+#else
+  // Mirrors SetCurrentThreadPriority()'s implementation.
+  ThreadPriority platform_specific_priority;
+  if (internal::GetCurrentThreadPriorityForPlatform(
+          &platform_specific_priority)) {
+    return platform_specific_priority;
+  }
+
+  // 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, 0);
+  if (errno != 0) {
+    DVPLOG(1) << "Failed to get nice value of thread ("
+              << PlatformThread::CurrentId() << ")";
+    return ThreadPriority::NORMAL;
+  }
+
+  return internal::NiceValueToThreadPriority(nice_value);
+#endif  // !defined(OS_NACL)
+}
+
+#endif  // !defined(OS_MACOSX)
+
+}  // namespace base
diff --git a/libchrome/base/threading/platform_thread_unittest.cc b/libchrome/base/threading/platform_thread_unittest.cc
new file mode 100644
index 0000000..2d99ed8
--- /dev/null
+++ b/libchrome/base/threading/platform_thread_unittest.cc
@@ -0,0 +1,365 @@
+// Copyright (c) 2012 The Chromium Authors. 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 "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX)
+#include <sys/types.h>
+#include <unistd.h>
+#include "base/threading/platform_thread_internal_posix.h"
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+// Trivial tests that thread runs and doesn't crash on create, join, or detach -
+
+namespace {
+
+class TrivialThread : public PlatformThread::Delegate {
+ public:
+  TrivialThread() : run_event_(WaitableEvent::ResetPolicy::MANUAL,
+                               WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+  void ThreadMain() override { run_event_.Signal(); }
+
+  WaitableEvent& run_event() { return run_event_; }
+
+ private:
+  WaitableEvent run_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrivialThread);
+};
+
+}  // namespace
+
+TEST(PlatformThreadTest, TrivialJoin) {
+  TrivialThread thread;
+  PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.run_event().IsSignaled());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  PlatformThread::Join(handle);
+  ASSERT_TRUE(thread.run_event().IsSignaled());
+}
+
+TEST(PlatformThreadTest, TrivialJoinTimesTen) {
+  TrivialThread thread[10];
+  PlatformThreadHandle handle[arraysize(thread)];
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].run_event().IsSignaled());
+  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].run_event().IsSignaled());
+}
+
+// The following detach tests are by nature racy. The run_event approximates the
+// end and termination of the thread, but threads could persist shortly after
+// the test completes.
+TEST(PlatformThreadTest, TrivialDetach) {
+  TrivialThread thread;
+  PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.run_event().IsSignaled());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  PlatformThread::Detach(handle);
+  thread.run_event().Wait();
+}
+
+TEST(PlatformThreadTest, TrivialDetachTimesTen) {
+  TrivialThread thread[10];
+  PlatformThreadHandle handle[arraysize(thread)];
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].run_event().IsSignaled());
+  for (size_t n = 0; n < arraysize(thread); n++) {
+    ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+    PlatformThread::Detach(handle[n]);
+  }
+  for (size_t n = 0; n < arraysize(thread); n++)
+    thread[n].run_event().Wait();
+}
+
+// Tests of basic thread functions ---------------------------------------------
+
+namespace {
+
+class FunctionTestThread : public PlatformThread::Delegate {
+ public:
+  FunctionTestThread()
+      : thread_id_(kInvalidThreadId),
+        termination_ready_(WaitableEvent::ResetPolicy::MANUAL,
+                           WaitableEvent::InitialState::NOT_SIGNALED),
+        terminate_thread_(WaitableEvent::ResetPolicy::MANUAL,
+                          WaitableEvent::InitialState::NOT_SIGNALED),
+        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_|, runs an optional test on that thread, signals
+  // |termination_ready_|, 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());
+
+    // Run extra tests.
+    RunTest();
+
+    termination_ready_.Signal();
+    terminate_thread_.Wait();
+
+    done_ = true;
+  }
+
+  PlatformThreadId thread_id() const {
+    EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
+    return thread_id_;
+  }
+
+  bool IsRunning() const {
+    return termination_ready_.IsSignaled() && !done_;
+  }
+
+  // Blocks until this thread is started and ready to be terminated.
+  void WaitForTerminationReady() { termination_ready_.Wait(); }
+
+  // Marks this thread for termination (callers must then join this thread to be
+  // guaranteed of termination).
+  void MarkForTermination() { terminate_thread_.Signal(); }
+
+ private:
+  // Runs an optional test on the newly created thread.
+  virtual void RunTest() {}
+
+  PlatformThreadId thread_id_;
+
+  mutable WaitableEvent termination_ready_;
+  WaitableEvent terminate_thread_;
+  bool done_;
+
+  DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
+};
+
+}  // namespace
+
+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.WaitForTerminationReady();
+  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].WaitForTerminationReady();
+
+  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[] = {
+// The order should be higher to lower to cover as much cases as possible on
+// Linux trybots running without CAP_SYS_NICE permission.
+#if !defined(OS_ANDROID)
+    // PlatformThread::GetCurrentThreadPriority() on Android does not support
+    // REALTIME_AUDIO case. See http://crbug.com/505474.
+    ThreadPriority::REALTIME_AUDIO,
+#endif
+    ThreadPriority::DISPLAY,
+    // This redundant BACKGROUND priority is to test backgrounding from other
+    // priorities, and unbackgrounding.
+    ThreadPriority::BACKGROUND,
+    ThreadPriority::NORMAL,
+    ThreadPriority::BACKGROUND};
+
+bool IsBumpingPriorityAllowed() {
+#if defined(OS_POSIX)
+  // Only root can raise thread priority on POSIX environment. On Linux, users
+  // who have CAP_SYS_NICE permission also can raise the thread priority, but
+  // libcap.so would be needed to check the capability.
+  return geteuid() == 0;
+#else
+  return true;
+#endif
+}
+
+class ThreadPriorityTestThread : public FunctionTestThread {
+ public:
+  explicit ThreadPriorityTestThread(ThreadPriority priority)
+      : priority_(priority) {}
+  ~ThreadPriorityTestThread() override = default;
+
+ private:
+  void RunTest() override {
+    // Confirm that the current thread's priority is as expected.
+    EXPECT_EQ(ThreadPriority::NORMAL,
+              PlatformThread::GetCurrentThreadPriority());
+
+    // Alter and verify the current thread's priority.
+    PlatformThread::SetCurrentThreadPriority(priority_);
+    EXPECT_EQ(priority_, PlatformThread::GetCurrentThreadPriority());
+  }
+
+  const ThreadPriority priority_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
+};
+
+}  // namespace
+
+// Test changing a created thread's priority (which has different semantics on
+// some platforms).
+TEST(PlatformThreadTest, ThreadPriorityCurrentThread) {
+  const bool bumping_priority_allowed = IsBumpingPriorityAllowed();
+  if (bumping_priority_allowed) {
+    // Bump the priority in order to verify that new threads are started with
+    // normal priority.
+    PlatformThread::SetCurrentThreadPriority(ThreadPriority::DISPLAY);
+  }
+
+  // Toggle each supported priority on the thread and confirm it affects it.
+  for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+    if (!bumping_priority_allowed &&
+        kThreadPriorityTestValues[i] >
+            PlatformThread::GetCurrentThreadPriority()) {
+      continue;
+    }
+
+    ThreadPriorityTestThread thread(kThreadPriorityTestValues[i]);
+    PlatformThreadHandle handle;
+
+    ASSERT_FALSE(thread.IsRunning());
+    ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+    thread.WaitForTerminationReady();
+    ASSERT_TRUE(thread.IsRunning());
+
+    thread.MarkForTermination();
+    PlatformThread::Join(handle);
+    ASSERT_FALSE(thread.IsRunning());
+  }
+}
+
+// Test for a function defined in platform_thread_internal_posix.cc. On OSX and
+// iOS, platform_thread_internal_posix.cc is not compiled, so these platforms
+// are excluded here, too.
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
+TEST(PlatformThreadTest, GetNiceValueToThreadPriority) {
+  using internal::NiceValueToThreadPriority;
+  using internal::kThreadPriorityToNiceValueMap;
+
+  EXPECT_EQ(ThreadPriority::BACKGROUND,
+            kThreadPriorityToNiceValueMap[0].priority);
+  EXPECT_EQ(ThreadPriority::NORMAL,
+            kThreadPriorityToNiceValueMap[1].priority);
+  EXPECT_EQ(ThreadPriority::DISPLAY,
+            kThreadPriorityToNiceValueMap[2].priority);
+  EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
+            kThreadPriorityToNiceValueMap[3].priority);
+
+  static const int kBackgroundNiceValue =
+      kThreadPriorityToNiceValueMap[0].nice_value;
+  static const int kNormalNiceValue =
+      kThreadPriorityToNiceValueMap[1].nice_value;
+  static const int kDisplayNiceValue =
+      kThreadPriorityToNiceValueMap[2].nice_value;
+  static const int kRealtimeAudioNiceValue =
+      kThreadPriorityToNiceValueMap[3].nice_value;
+
+  // The tests below assume the nice values specified in the map are within
+  // the range below (both ends exclusive).
+  static const int kHighestNiceValue = 19;
+  static const int kLowestNiceValue = -20;
+
+  EXPECT_GT(kHighestNiceValue, kBackgroundNiceValue);
+  EXPECT_GT(kBackgroundNiceValue, kNormalNiceValue);
+  EXPECT_GT(kNormalNiceValue, kDisplayNiceValue);
+  EXPECT_GT(kDisplayNiceValue, kRealtimeAudioNiceValue);
+  EXPECT_GT(kRealtimeAudioNiceValue, kLowestNiceValue);
+
+  EXPECT_EQ(ThreadPriority::BACKGROUND,
+            NiceValueToThreadPriority(kHighestNiceValue));
+  EXPECT_EQ(ThreadPriority::BACKGROUND,
+            NiceValueToThreadPriority(kBackgroundNiceValue + 1));
+  EXPECT_EQ(ThreadPriority::BACKGROUND,
+            NiceValueToThreadPriority(kBackgroundNiceValue));
+  EXPECT_EQ(ThreadPriority::BACKGROUND,
+            NiceValueToThreadPriority(kNormalNiceValue + 1));
+  EXPECT_EQ(ThreadPriority::NORMAL,
+            NiceValueToThreadPriority(kNormalNiceValue));
+  EXPECT_EQ(ThreadPriority::NORMAL,
+            NiceValueToThreadPriority(kDisplayNiceValue + 1));
+  EXPECT_EQ(ThreadPriority::DISPLAY,
+            NiceValueToThreadPriority(kDisplayNiceValue));
+  EXPECT_EQ(ThreadPriority::DISPLAY,
+            NiceValueToThreadPriority(kRealtimeAudioNiceValue + 1));
+  EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
+            NiceValueToThreadPriority(kRealtimeAudioNiceValue));
+  EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
+            NiceValueToThreadPriority(kLowestNiceValue));
+}
+#endif
+
+}  // namespace base
diff --git a/libchrome/base/threading/post_task_and_reply_impl.cc b/libchrome/base/threading/post_task_and_reply_impl.cc
new file mode 100644
index 0000000..c906866
--- /dev/null
+++ b/libchrome/base/threading/post_task_and_reply_impl.cc
@@ -0,0 +1,94 @@
+// 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/threading/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) {
+  // TODO(tzik): Use DCHECK here once the crash is gone. http://crbug.com/541319
+  CHECK(!task.is_null()) << from_here.ToString();
+  CHECK(!reply.is_null()) << from_here.ToString();
+  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/libchrome/base/threading/post_task_and_reply_impl.h b/libchrome/base/threading/post_task_and_reply_impl.h
new file mode 100644
index 0000000..d21ab78
--- /dev/null
+++ b/libchrome/base/threading/post_task_and_reply_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.
+
+// 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:
+  virtual ~PostTaskAndReplyImpl() = default;
+
+  // 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/libchrome/base/threading/sequenced_task_runner_handle.cc b/libchrome/base/threading/sequenced_task_runner_handle.cc
new file mode 100644
index 0000000..88b36a8
--- /dev/null
+++ b/libchrome/base/threading/sequenced_task_runner_handle.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/threading/sequenced_task_runner_handle.h"
+
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<SequencedTaskRunnerHandle>>::Leaky
+    lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// static
+scoped_refptr<SequencedTaskRunner> SequencedTaskRunnerHandle::Get() {
+  // Return the registered SequencedTaskRunner, if any.
+  const SequencedTaskRunnerHandle* handle = lazy_tls_ptr.Pointer()->Get();
+  if (handle) {
+    // Various modes of setting SequencedTaskRunnerHandle don't combine.
+    DCHECK(!base::ThreadTaskRunnerHandle::IsSet());
+    DCHECK(!SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread());
+    return handle->task_runner_;
+  }
+
+  // Return the SequencedTaskRunner obtained from SequencedWorkerPool, if any.
+  scoped_refptr<base::SequencedTaskRunner> task_runner =
+      SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
+  if (task_runner) {
+    DCHECK(!base::ThreadTaskRunnerHandle::IsSet());
+    return task_runner;
+  }
+
+  // Return the SingleThreadTaskRunner for the current thread otherwise.
+  return base::ThreadTaskRunnerHandle::Get();
+}
+
+// static
+bool SequencedTaskRunnerHandle::IsSet() {
+  return lazy_tls_ptr.Pointer()->Get() ||
+         SequencedWorkerPool::GetWorkerPoolForCurrentThread() ||
+         base::ThreadTaskRunnerHandle::IsSet();
+}
+
+SequencedTaskRunnerHandle::SequencedTaskRunnerHandle(
+    scoped_refptr<SequencedTaskRunner> task_runner)
+    : task_runner_(std::move(task_runner)) {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK(!SequencedTaskRunnerHandle::IsSet());
+  lazy_tls_ptr.Pointer()->Set(this);
+}
+
+SequencedTaskRunnerHandle::~SequencedTaskRunnerHandle() {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
+  DCHECK_EQ(lazy_tls_ptr.Pointer()->Get(), this);
+  lazy_tls_ptr.Pointer()->Set(nullptr);
+}
+
+}  // namespace base
diff --git a/libchrome/base/threading/sequenced_task_runner_handle.h b/libchrome/base/threading/sequenced_task_runner_handle.h
new file mode 100644
index 0000000..e6dec1e
--- /dev/null
+++ b/libchrome/base/threading/sequenced_task_runner_handle.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_SEQUENCED_TASK_RUNNER_HANDLE_H_
+#define BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+
+namespace base {
+
+class BASE_EXPORT SequencedTaskRunnerHandle {
+ public:
+  // Returns a SequencedTaskRunner which guarantees that posted tasks will only
+  // run after the current task is finished and will satisfy a SequenceChecker.
+  // It should only be called if IsSet() returns true (see the comment there for
+  // the requirements).
+  static scoped_refptr<SequencedTaskRunner> Get();
+
+  // Returns true if one of the following conditions is fulfilled:
+  // a) A SequencedTaskRunner has been assigned to the current thread by
+  //    instantiating a SequencedTaskRunnerHandle.
+  // b) The current thread has a ThreadTaskRunnerHandle (which includes any
+  //    thread that has a MessageLoop associated with it), or
+  // c) The current thread is a worker thread belonging to a
+  //    SequencedWorkerPool.
+  static bool IsSet();
+
+  // Binds |task_runner| to the current thread.
+  explicit SequencedTaskRunnerHandle(
+      scoped_refptr<SequencedTaskRunner> task_runner);
+  ~SequencedTaskRunnerHandle();
+
+ private:
+  scoped_refptr<SequencedTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedTaskRunnerHandle);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
diff --git a/libchrome/base/threading/sequenced_worker_pool.cc b/libchrome/base/threading/sequenced_worker_pool.cc
new file mode 100644
index 0000000..57961b5
--- /dev/null
+++ b/libchrome/base/threading/sequenced_worker_pool.cc
@@ -0,0 +1,1408 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.h>
+
+#include <list>
+#include <map>
+#include <memory>
+#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/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.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/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/trace_event/heap_profiler.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+#include "build/build_config.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_t 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(
+      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(
+    scoped_refptr<SequencedWorkerPool> pool,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(std::move(pool)), shutdown_behavior_(shutdown_behavior) {}
+
+SequencedWorkerPoolTaskRunner::~SequencedWorkerPoolTaskRunner() {
+}
+
+bool SequencedWorkerPoolTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  if (delay.is_zero()) {
+    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(
+      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(
+    scoped_refptr<SequencedWorkerPool> pool,
+    SequencedWorkerPool::SequenceToken token,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(std::move(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.is_zero()) {
+    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_t GetTaskTraceID(const SequencedTask& task, void* pool) {
+  return (static_cast<uint64_t>(task.trace_id) << 32) |
+         static_cast<uint64_t>(reinterpret_cast<intptr_t>(pool));
+}
+
+}  // 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(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;
+
+  // Gets the worker for the current thread out of thread-local storage.
+  static Worker* GetForCurrentThread();
+
+  // 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_;
+  }
+
+  scoped_refptr<SequencedWorkerPool> worker_pool() const {
+    return worker_pool_;
+  }
+
+ private:
+  static LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+      lazy_tls_ptr_;
+
+  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();
+
+  static 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;
+
+  bool IsRunningSequence(SequenceToken sequence_token) const;
+
+  void SetRunningTaskInfoForCurrentThread(SequenceToken sequence_token,
+                                          WorkerShutdown shutdown_behavior);
+
+  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_t 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.
+  using ThreadMap = std::map<PlatformThreadId, std::unique_ptr<Worker>>;
+  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_t 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(
+    scoped_refptr<SequencedWorkerPool> worker_pool,
+    int thread_number,
+    const std::string& prefix)
+    : SimpleThread(prefix + StringPrintf("Worker%d", thread_number)),
+      worker_pool_(std::move(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 this worker in thread local storage for static function
+  // access.
+  DCHECK(!lazy_tls_ptr_.Get().Get());
+  lazy_tls_ptr_.Get().Set(this);
+
+  // 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_ = nullptr;
+}
+
+// static
+SequencedWorkerPool::Worker*
+SequencedWorkerPool::Worker::GetForCurrentThread() {
+  // Don't construct lazy instance on check.
+  if (lazy_tls_ptr_ == nullptr)
+    return nullptr;
+
+  return lazy_tls_ptr_.Get().Get();
+}
+
+// static
+LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+    SequencedWorkerPool::Worker::lazy_tls_ptr_ = LAZY_INSTANCE_INITIALIZER;
+
+// 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();
+}
+
+// static
+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.is_zero() || 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_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+        "SequencedWorkerPool::Inner::PostTask",
+        TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this))),
+        TRACE_EVENT_FLAG_FLOW_OUT);
+
+    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());
+}
+
+bool SequencedWorkerPool::Inner::IsRunningSequence(
+    SequenceToken sequence_token) const {
+  DCHECK(sequence_token.IsValid());
+  AutoLock lock(lock_);
+  return !IsSequenceTokenRunnable(sequence_token.id_);
+}
+
+void SequencedWorkerPool::Inner::SetRunningTaskInfoForCurrentThread(
+    SequenceToken sequence_token,
+    WorkerShutdown shutdown_behavior) {
+  AutoLock lock(lock_);
+  ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
+  DCHECK(found != threads_.end());
+  DCHECK(found->second->is_processing_task());
+  DCHECK(!found->second->task_sequence_token().IsValid());
+  found->second->set_running_task_info(sequence_token, shutdown_behavior);
+
+  // Mark the sequence token as in use.
+  bool success = current_sequences_.insert(sequence_token.id_).second;
+  DCHECK(success);
+}
+
+// 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;
+    auto result = threads_.insert(
+        std::make_pair(this_worker->tid(), WrapUnique(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_WITH_FLOW2(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+            "SequencedWorkerPool::Inner::ThreadLoop",
+            TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this))),
+            TRACE_EVENT_FLAG_FLOW_IN,
+            "src_file", task.posted_from.file_name(),
+            "src_func", task.posted_from.function_name());
+        TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION task_event(
+            task.posted_from.file_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);
+
+          // Update the sequence token in case it has been set from within the
+          // task, so it can be removed from the set of currently running
+          // sequences in DidRunWorkerTask() below.
+          task.sequence_token_id = this_worker->task_sequence_token().id_;
+
+          // 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_t 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 --------------------------------------------------------
+
+std::string SequencedWorkerPool::SequenceToken::ToString() const {
+  return base::StringPrintf("[%d]", id_);
+}
+
+// static
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::GetSequenceTokenForCurrentThread() {
+  Worker* worker = Worker::GetForCurrentThread();
+  if (!worker)
+    return SequenceToken();
+
+  return worker->task_sequence_token();
+}
+
+// static
+scoped_refptr<SequencedWorkerPool>
+SequencedWorkerPool::GetWorkerPoolForCurrentThread() {
+  Worker* worker = Worker::GetForCurrentThread();
+  if (!worker)
+    return nullptr;
+
+  return worker->worker_pool();
+}
+
+// static
+scoped_refptr<SequencedTaskRunner>
+SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread() {
+  Worker* worker = Worker::GetForCurrentThread();
+
+  // If there is no worker, this thread is not a worker thread. Otherwise, it is
+  // currently running a task (sequenced or unsequenced).
+  if (!worker)
+    return nullptr;
+
+  scoped_refptr<SequencedWorkerPool> pool = worker->worker_pool();
+  SequenceToken sequence_token = worker->task_sequence_token();
+  WorkerShutdown shutdown_behavior = worker->task_shutdown_behavior();
+  if (!sequence_token.IsValid()) {
+    // Create a new sequence token and bind this thread to it, to make sure that
+    // a task posted to the SequencedTaskRunner we are going to return is not
+    // immediately going to run on a different thread.
+    sequence_token = Inner::GetSequenceToken();
+    pool->inner_->SetRunningTaskInfoForCurrentThread(sequence_token,
+                                                     shutdown_behavior);
+  }
+
+  DCHECK(pool->IsRunningSequenceOnCurrentThread(sequence_token));
+  return new SequencedWorkerPoolSequencedTaskRunner(
+      std::move(pool), sequence_token, shutdown_behavior);
+}
+
+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;
+  }
+}
+
+// static
+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.is_zero() ? 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.is_zero() ? 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);
+}
+
+bool SequencedWorkerPool::IsRunningSequence(
+    SequenceToken sequence_token) const {
+  return inner_->IsRunningSequence(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/libchrome/base/threading/sequenced_worker_pool.h b/libchrome/base/threading/sequenced_worker_pool.h
new file mode 100644
index 0000000..cbec395
--- /dev/null
+++ b/libchrome/base/threading/sequenced_worker_pool.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_THREADING_SEQUENCED_WORKER_POOL_H_
+#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+
+#include <stddef.h>
+
+#include <cstddef>
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.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 =
+//       SequencedWorkerPool::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 BASE_EXPORT 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;
+    }
+
+    // Returns a string representation of this token. This method should only be
+    // used for debugging.
+    std::string ToString() const;
+
+   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();
+
+  // Gets a SequencedTaskRunner for the current thread. If the current thread is
+  // running an unsequenced task, a new SequenceToken will be generated and set,
+  // so that the returned SequencedTaskRunner is guaranteed to run tasks after
+  // the current task has finished running.
+  static scoped_refptr<SequencedTaskRunner>
+  GetSequencedTaskRunnerForCurrentThread();
+
+  // Returns a unique token that can be used to sequence tasks posted to
+  // PostSequencedWorkerTask(). Valid tokens are always nonzero.
+  // TODO(bauerb): Rename this to better differentiate from
+  // GetSequenceTokenForCurrentThread().
+  static SequenceToken GetSequenceToken();
+
+  // Returns the SequencedWorkerPool that owns this thread, or null if the
+  // current thread is not a SequencedWorkerPool worker thread.
+  static scoped_refptr<SequencedWorkerPool> GetWorkerPoolForCurrentThread();
+
+  // When constructing a SequencedWorkerPool, there must be a
+  // ThreadTaskRunnerHandle 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 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;
+
+  // Returns true if any thread is currently processing a task with the given
+  // sequence token. Should only be called with a valid sequence token.
+  bool IsRunningSequence(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 std::unique_ptr<Inner> inner_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SEQUENCED_WORKER_POOL_H_
diff --git a/libchrome/base/threading/simple_thread.cc b/libchrome/base/threading/simple_thread.cc
new file mode 100644
index 0000000..6c64a17
--- /dev/null
+++ b/libchrome/base/threading/simple_thread.cc
@@ -0,0 +1,174 @@
+// 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_(WaitableEvent::ResetPolicy::MANUAL,
+             WaitableEvent::InitialState::NOT_SIGNALED),
+      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_(WaitableEvent::ResetPolicy::MANUAL,
+             WaitableEvent::InitialState::NOT_SIGNALED),
+      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_(WaitableEvent::ResetPolicy::MANUAL,
+           WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+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/libchrome/base/threading/simple_thread.h b/libchrome/base/threading/simple_thread.h
new file mode 100644
index 0000000..3deeb10
--- /dev/null
+++ b/libchrome/base/threading/simple_thread.h
@@ -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.
+
+// 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 <stddef.h>
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.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) {}
+    explicit Options(ThreadPriority priority)
+        : stack_size_(0), priority_(priority) {}
+    ~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;
+
+ 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/libchrome/base/threading/simple_thread_unittest.cc b/libchrome/base/threading/simple_thread_unittest.cc
new file mode 100644
index 0000000..14dd459
--- /dev/null
+++ b/libchrome/base/threading/simple_thread_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2012 The Chromium Authors. All 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(WaitableEvent::ResetPolicy::MANUAL,
+                      WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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(WaitableEvent::ResetPolicy::MANUAL,
+                      WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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(WaitableEvent::ResetPolicy::MANUAL,
+                      WaitableEvent::InitialState::NOT_SIGNALED);
+  // 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/libchrome/base/threading/thread.cc b/libchrome/base/threading/thread.cc
new file mode 100644
index 0000000..9cdc691
--- /dev/null
+++ b/libchrome/base/threading/thread.cc
@@ -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.
+
+#include "base/threading/thread.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.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(const Options& other) = default;
+
+Thread::Options::~Options() {
+}
+
+Thread::Thread(const std::string& name)
+    :
+#if defined(OS_WIN)
+      com_status_(NONE),
+#endif
+      stopping_(false),
+      running_(false),
+      thread_(0),
+      id_(kInvalidThreadId),
+      id_event_(WaitableEvent::ResetPolicy::MANUAL,
+                WaitableEvent::InitialState::NOT_SIGNALED),
+      message_loop_(nullptr),
+      message_loop_timer_slack_(TIMER_SLACK_NONE),
+      name_(name),
+      start_event_(WaitableEvent::ResetPolicy::MANUAL,
+                   WaitableEvent::InitialState::NOT_SIGNALED) {
+}
+
+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
+
+  // Reset |id_| here to support restarting the thread.
+  id_event_.Reset();
+  id_ = kInvalidThreadId;
+
+  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;
+  std::unique_ptr<MessageLoop> message_loop =
+      MessageLoop::CreateUnbound(type, options.message_pump_factory);
+  message_loop_ = message_loop.get();
+  start_event_.Reset();
+
+  // 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_);
+    if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,
+                                            options.priority)) {
+      DLOG(ERROR) << "failed to create thread";
+      message_loop_ = nullptr;
+      return false;
+    }
+  }
+
+  // The ownership of message_loop is managemed by the newly created thread
+  // within the ThreadMain.
+  ignore_result(message_loop.release());
+
+  DCHECK(message_loop_);
+  return true;
+}
+
+bool Thread::StartAndWaitForTesting() {
+  bool result = Start();
+  if (!result)
+    return false;
+  WaitUntilThreadStarted();
+  return true;
+}
+
+bool Thread::WaitUntilThreadStarted() const {
+  if (!message_loop_)
+    return false;
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  start_event_.Wait();
+  return true;
+}
+
+void Thread::Stop() {
+  AutoLock lock(thread_lock_);
+  if (thread_.is_null())
+    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_);
+  thread_ = base::PlatformThreadHandle();
+
+  // The thread should nullify message_loop_ on exit.
+  DCHECK(!message_loop_);
+
+  stopping_ = false;
+}
+
+void Thread::StopSoon() {
+  // We should only be called on the same thread that started us.
+
+  DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
+
+  if (stopping_ || !message_loop_)
+    return;
+
+  stopping_ = true;
+  task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+}
+
+PlatformThreadId Thread::GetThreadId() const {
+  // If the thread is created but not started yet, wait for |id_| being ready.
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  id_event_.Wait();
+  return 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::Run(MessageLoop*) {
+  RunLoop().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() {
+  // First, make GetThreadId() available to avoid deadlocks. It could be called
+  // any place in the following thread initialization code.
+  id_ = PlatformThread::CurrentId();
+  DCHECK_NE(kInvalidThreadId, id_);
+  id_event_.Signal();
+
+  // Complete the initialization of our Thread object.
+  PlatformThread::SetName(name_.c_str());
+
+  // Lazily initialize the message_loop so that it can run on this thread.
+  DCHECK(message_loop_);
+  std::unique_ptr<MessageLoop> message_loop(message_loop_);
+  message_loop_->BindToCurrentThread();
+  message_loop_->SetTimerSlack(message_loop_timer_slack_);
+
+#if defined(OS_WIN)
+  std::unique_ptr<win::ScopedCOMInitializer> com_initializer;
+  if (com_status_ != NONE) {
+    com_initializer.reset((com_status_ == STA) ?
+        new win::ScopedCOMInitializer() :
+        new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
+  }
+#endif
+
+  // Let the thread do extra initialization.
+  Init();
+
+  {
+    AutoLock lock(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
+
+  if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
+    // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper.
+    // Don't check for custom message pumps, because their shutdown might not
+    // allow this.
+    DCHECK(GetThreadWasQuitProperly());
+  }
+
+  // We can't receive messages anymore.
+  // (The message loop is destructed at the end of this block)
+  message_loop_ = nullptr;
+}
+
+}  // namespace base
diff --git a/libchrome/base/threading/thread.h b/libchrome/base/threading/thread.h
new file mode 100644
index 0000000..c9a77d7
--- /dev/null
+++ b/libchrome/base/threading/thread.h
@@ -0,0 +1,262 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/macros.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/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class MessagePump;
+
+// 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<std::unique_ptr<MessagePump>()> MessagePumpFactory;
+
+    Options();
+    Options(MessageLoop::Type type, size_t size);
+    Options(const Options& other);
+    ~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(!message_loop_);
+    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() const;
+
+  // 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 nullptr.
+  //
+  // 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 TaskRunner for this thread. Use the TaskRunner's PostTask
+  // methods to execute code on the thread. Returns nullptr 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_; }
+
+  // Returns the thread ID.  Should not be called before the first Start*()
+  // call.  Keeps on returning the same ID even after a Stop() call. The next
+  // Start*() call renews the ID.
+  //
+  // WARNING: This function will block if the thread hasn't started yet.
+  //
+  PlatformThreadId GetThreadId() const;
+
+  // Returns true if the thread has been started, and not yet stopped.
+  bool IsRunning() const;
+
+ 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-nullptr and invalid.
+  // Should be written on the thread that created this thread. Also read data
+  // could be wrong on other threads.
+  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 id once it has started.
+  PlatformThreadId id_;
+  mutable WaitableEvent id_event_;  // Protects |id_|.
+
+  // 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_;
+
+  // Signaled when the created thread gets ready to use the message loop.
+  mutable WaitableEvent start_event_;
+
+  friend void ThreadQuitHelper();
+
+  DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_H_
diff --git a/libchrome/base/threading/thread_checker.h b/libchrome/base/threading/thread_checker.h
new file mode 100644
index 0000000..1d970f0
--- /dev/null
+++ b/libchrome/base/threading/thread_checker.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_THREADING_THREAD_CHECKER_H_
+#define BASE_THREADING_THREAD_CHECKER_H_
+
+#include "base/logging.h"
+#include "base/threading/thread_checker_impl.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.
+#if DCHECK_IS_ON()
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+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/libchrome/base/threading/thread_checker_impl.cc b/libchrome/base/threading/thread_checker_impl.cc
new file mode 100644
index 0000000..eb87bae
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/thread_checker_impl.h b/libchrome/base/threading/thread_checker_impl.h
new file mode 100644
index 0000000..c92e143
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/thread_checker_unittest.cc b/libchrome/base/threading/thread_checker_unittest.cc
new file mode 100644
index 0000000..bc5b1e4
--- /dev/null
+++ b/libchrome/base/threading/thread_checker_unittest.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.
+
+#include "base/threading/thread_checker.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.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:
+  std::unique_ptr<ThreadCheckerClass> thread_checker_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
+};
+
+}  // namespace
+
+TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
+  std::unique_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) {
+  std::unique_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) {
+  std::unique_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() {
+  std::unique_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() {
+  std::unique_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/libchrome/base/threading/thread_collision_warner.cc b/libchrome/base/threading/thread_collision_warner.cc
new file mode 100644
index 0000000..547e11c
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/thread_collision_warner.h b/libchrome/base/threading/thread_collision_warner.h
new file mode 100644
index 0000000..4699a91
--- /dev/null
+++ b/libchrome/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/compiler_specific.h"
+#include "base/macros.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/libchrome/base/threading/thread_collision_warner_unittest.cc b/libchrome/base/threading/thread_collision_warner_unittest.cc
new file mode 100644
index 0000000..71447ef
--- /dev/null
+++ b/libchrome/base/threading/thread_collision_warner_unittest.cc
@@ -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.
+
+#include "base/threading/thread_collision_warner.h"
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.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) std::unique_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/libchrome/base/threading/thread_id_name_manager.cc b/libchrome/base/threading/thread_id_name_manager.cc
new file mode 100644
index 0000000..107e0dc
--- /dev/null
+++ b/libchrome/base/threading/thread_id_name_manager.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.
+
+#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"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.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) {
+  std::string* leaked_str = NULL;
+  {
+    AutoLock locked(lock_);
+    NameToInternedNameMap::iterator iter = name_to_interned_name_.find(name);
+    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;
+  }
+
+  // Add the leaked thread name to heap profiler context tracker. The name added
+  // is valid for the lifetime of the process. AllocationContextTracker cannot
+  // call GetName(which holds a lock) during the first allocation because it can
+  // cause a deadlock when the first allocation happens in the
+  // ThreadIdNameManager itself when holding the lock.
+  trace_event::AllocationContextTracker::SetCurrentThreadName(
+      leaked_str->c_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/libchrome/base/threading/thread_id_name_manager.h b/libchrome/base/threading/thread_id_name_manager.h
new file mode 100644
index 0000000..f469b60
--- /dev/null
+++ b/libchrome/base/threading/thread_id_name_manager.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_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/macros.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+template <typename T>
+struct DefaultSingletonTraits;
+
+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/libchrome/base/threading/thread_id_name_manager_unittest.cc b/libchrome/base/threading/thread_id_name_manager_unittest.cc
new file mode 100644
index 0000000..350dc0f
--- /dev/null
+++ b/libchrome/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.GetThreadId()));
+  EXPECT_STREQ(kBThread, manager->GetName(thread_b.GetThreadId()));
+
+  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.GetThreadId()));
+
+  thread_a.Stop();
+  EXPECT_STREQ("", manager->GetName(thread_a.GetThreadId()));
+}
+
+TEST_F(ThreadIdNameManagerTest, RestartThread) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+  base::Thread thread_a(kAThread);
+
+  thread_a.StartAndWaitForTesting();
+  base::PlatformThreadId a_id = thread_a.GetThreadId();
+  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.GetThreadId()));
+  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/libchrome/base/threading/thread_local.h b/libchrome/base/threading/thread_local.h
new file mode 100644
index 0000000..f40420c
--- /dev/null
+++ b/libchrome/base/threading/thread_local.h
@@ -0,0 +1,134 @@
+// 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/macros.h"
+#include "base/threading/thread_local_storage.h"
+#include "build/build_config.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/libchrome/base/threading/thread_local_posix.cc b/libchrome/base/threading/thread_local_posix.cc
new file mode 100644
index 0000000..8bc46ad
--- /dev/null
+++ b/libchrome/base/threading/thread_local_posix.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/threading/thread_local.h"
+
+#include <pthread.h>
+
+#include "base/logging.h"
+#include "build/build_config.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/libchrome/base/threading/thread_local_storage.cc b/libchrome/base/threading/thread_local_storage.cc
new file mode 100644
index 0000000..a7eb527
--- /dev/null
+++ b/libchrome/base/threading/thread_local_storage.cc
@@ -0,0 +1,252 @@
+// 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"
+#include "build/build_config.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 !=
+        static_cast<PlatformThreadLocalStorage::TLSKey>(
+            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) {
+  slot_ = 0;
+  base::subtle::Release_Store(&initialized_, 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;
+  base::subtle::Release_Store(&initialized_, 1);
+}
+
+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;
+  base::subtle::Release_Store(&initialized_, 0);
+}
+
+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/libchrome/base/threading/thread_local_storage.h b/libchrome/base/threading/thread_local_storage.h
new file mode 100644
index 0000000..0c7a692
--- /dev/null
+++ b/libchrome/base/threading/thread_local_storage.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.
+
+#ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "build/build_config.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 : unsigned { 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 {false, 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 base::subtle::Acquire_Load(&initialized_) != 0;
+    }
+
+    // The internals of this struct should be considered private.
+    base::subtle::Atomic32 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/libchrome/base/threading/thread_local_storage_posix.cc b/libchrome/base/threading/thread_local_storage_posix.cc
new file mode 100644
index 0000000..ebaf400
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/thread_local_storage_unittest.cc b/libchrome/base/threading/thread_local_storage_unittest.cc
new file mode 100644
index 0000000..322524b
--- /dev/null
+++ b/libchrome/base/threading/thread_local_storage_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.
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <process.h>
+#endif
+
+#include "base/macros.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local_storage.h"
+#include "build/build_config.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/libchrome/base/threading/thread_local_unittest.cc b/libchrome/base/threading/thread_local_unittest.cc
new file mode 100644
index 0000000..cdc1ca6
--- /dev/null
+++ b/libchrome/base/threading/thread_local_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2012 The Chromium Authors. All 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(WaitableEvent::ResetPolicy::MANUAL,
+                           WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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/libchrome/base/threading/thread_restrictions.cc b/libchrome/base/threading/thread_restrictions.cc
new file mode 100644
index 0000000..00306c5
--- /dev/null
+++ b/libchrome/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;
+
+}  // 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/libchrome/base/threading/thread_restrictions.h b/libchrome/base/threading/thread_restrictions.h
new file mode 100644
index 0000000..4212a4b
--- /dev/null
+++ b/libchrome/base/threading/thread_restrictions.h
@@ -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.
+
+#ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_
+#define BASE_THREADING_THREAD_RESTRICTIONS_H_
+
+#include "base/base_export.h"
+#include "base/macros.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 SingleThreadTaskGraphRunner;
+}
+namespace chromeos {
+class BlockingMethodCaller;
+namespace system {
+class StatisticsProviderImpl;
+}
+}
+namespace chrome_browser_net {
+class Predictor;
+}
+namespace content {
+class BrowserGpuChannelHostFactory;
+class BrowserGpuMemoryBufferManager;
+class BrowserShutdownProfileDumper;
+class BrowserSurfaceViewManager;
+class BrowserTestBase;
+class NestedMessagePumpAndroid;
+class ScopedAllowWaitForAndroidLayoutTests;
+class ScopedAllowWaitForDebugURL;
+class SoftwareOutputDeviceMus;
+class TextInputClientMac;
+class CategorizedWorkerPool;
+}  // namespace content
+namespace dbus {
+class Bus;
+}
+namespace disk_cache {
+class BackendImpl;
+class InFlightIO;
+}
+namespace gpu {
+class GpuChannelHost;
+}
+namespace mojo {
+namespace common {
+class MessagePumpMojo;
+}
+class SyncCallRestrictions;
+}
+namespace ui {
+class CommandBufferClientImpl;
+class CommandBufferLocal;
+class GpuState;
+}
+namespace net {
+class NetworkChangeNotifierMac;
+namespace internal {
+class AddressTrackerLinux;
+}
+}
+
+namespace remoting {
+class AutoThread;
+}
+
+namespace ui {
+class WindowResizeHelperMac;
+}
+
+namespace views {
+class ScreenMus;
+}
+
+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) { return true; }
+  static void AssertIOAllowed() {}
+  static bool SetSingletonAllowed(bool) { 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::BrowserSurfaceViewManager;
+  friend class content::BrowserTestBase;
+  friend class content::NestedMessagePumpAndroid;
+  friend class content::ScopedAllowWaitForAndroidLayoutTests;
+  friend class content::ScopedAllowWaitForDebugURL;
+  friend class ::HistogramSynchronizer;
+  friend class ::ScopedAllowWaitForLegacyWebViewApi;
+  friend class cc::CompletionEvent;
+  friend class cc::SingleThreadTaskGraphRunner;
+  friend class content::CategorizedWorkerPool;
+  friend class remoting::AutoThread;
+  friend class ui::WindowResizeHelperMac;
+  friend class MessagePumpDefault;
+  friend class SequencedWorkerPool;
+  friend class SimpleThread;
+  friend class Thread;
+  friend class ThreadTestHelper;
+  friend class PlatformThread;
+  friend class android::JavaHandlerThread;
+  friend class mojo::common::MessagePumpMojo;
+  friend class mojo::SyncCallRestrictions;
+  friend class ui::CommandBufferClientImpl;
+  friend class ui::CommandBufferLocal;
+  friend class ui::GpuState;
+
+  // 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::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 gpu::GpuChannelHost;               // http://crbug.com/125264
+  friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097
+  friend class net::NetworkChangeNotifierMac;     // http://crbug.com/125097
+  friend class ::BrowserProcessImpl;              // http://crbug.com/125207
+  friend class ::NativeBackendKWallet;            // http://crbug.com/125331
+#if !defined(OFFICIAL_BUILD)
+  friend class content::SoftwareOutputDeviceMus;  // Interim non-production code
+#endif
+  friend class views::ScreenMus;
+// END USAGE THAT NEEDS TO BE FIXED.
+
+#if ENABLE_THREAD_RESTRICTIONS
+  static bool SetWaitAllowed(bool allowed);
+#else
+  static bool SetWaitAllowed(bool) { 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/libchrome/base/threading/thread_task_runner_handle.cc b/libchrome/base/threading/thread_task_runner_handle.cc
new file mode 100644
index 0000000..190e18f
--- /dev/null
+++ b/libchrome/base/threading/thread_task_runner_handle.cc
@@ -0,0 +1,51 @@
+// Copyright 2016 The Chromium Authors. All 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_task_runner_handle.h"
+
+#include <utility>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle>>::Leaky
+    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();
+}
+
+ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
+    scoped_refptr<SingleThreadTaskRunner> task_runner)
+    : task_runner_(std::move(task_runner)) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  // No SequencedTaskRunnerHandle (which includes ThreadTaskRunnerHandles)
+  // should already be set for this thread.
+  DCHECK(!SequencedTaskRunnerHandle::IsSet());
+  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(nullptr);
+}
+
+}  // namespace base
diff --git a/libchrome/base/threading/thread_task_runner_handle.h b/libchrome/base/threading/thread_task_runner_handle.h
new file mode 100644
index 0000000..c8e5893
--- /dev/null
+++ b/libchrome/base/threading/thread_task_runner_handle.h
@@ -0,0 +1,43 @@
+// Copyright 2016 The Chromium Authors. All 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_TASK_RUNNER_HANDLE_H_
+#define BASE_THREADING_THREAD_TASK_RUNNER_HANDLE_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// 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.
+// Prefer SequenceTaskRunnerHandle to this unless thread affinity is required.
+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(
+      scoped_refptr<SingleThreadTaskRunner> task_runner);
+  ~ThreadTaskRunnerHandle();
+
+ private:
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadTaskRunnerHandle);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_TASK_RUNNER_HANDLE_H_
diff --git a/libchrome/base/threading/thread_unittest.cc b/libchrome/base/threading/thread_unittest.cc
new file mode 100644
index 0000000..b0fd265
--- /dev/null
+++ b/libchrome/base/threading/thread_unittest.cc
@@ -0,0 +1,299 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+using base::Thread;
+
+typedef PlatformTest ThreadTest;
+
+namespace {
+
+void ToggleValue(bool* value) {
+  *value = !*value;
+}
+
+class SleepInsideInitThread : public Thread {
+ public:
+  SleepInsideInitThread() : Thread("none") {
+    init_called_ = false;
+  }
+  ~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);
+}
+
+// Task that calls GetThreadId() of |thread|, stores the result into |id|, then
+// signal |event|.
+void ReturnThreadId(base::Thread* thread,
+                    base::PlatformThreadId* id,
+                    base::WaitableEvent* event) {
+  *id = thread->GetThreadId();
+  event->Signal();
+}
+
+}  // 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)
+  // ASan bloats the stack variables and overflows the 12 kb stack.
+  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());
+}
+
+TEST_F(ThreadTest, ThreadId) {
+  Thread a("ThreadId0");
+  Thread b("ThreadId1");
+  a.Start();
+  b.Start();
+
+  // Post a task that calls GetThreadId() on the created thread.
+  base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+                            base::WaitableEvent::InitialState::NOT_SIGNALED);
+  base::PlatformThreadId id_from_new_thread;
+  a.task_runner()->PostTask(
+      FROM_HERE, base::Bind(ReturnThreadId, &a, &id_from_new_thread, &event));
+
+  // Call GetThreadId() on the current thread before calling event.Wait() so
+  // that this test can find a race issue with TSAN.
+  base::PlatformThreadId id_from_current_thread = a.GetThreadId();
+
+  // Check if GetThreadId() returns consistent value in both threads.
+  event.Wait();
+  EXPECT_EQ(id_from_current_thread, id_from_new_thread);
+
+  // A started thread should have a valid ID.
+  EXPECT_NE(base::kInvalidThreadId, a.GetThreadId());
+  EXPECT_NE(base::kInvalidThreadId, b.GetThreadId());
+
+  // Each thread should have a different thread ID.
+  EXPECT_NE(a.GetThreadId(), b.GetThreadId());
+}
+
+TEST_F(ThreadTest, ThreadIdWithRestart) {
+  Thread a("ThreadIdWithRestart");
+  base::PlatformThreadId previous_id = base::kInvalidThreadId;
+
+  for (size_t i = 0; i < 16; ++i) {
+    EXPECT_TRUE(a.Start());
+    base::PlatformThreadId current_id = a.GetThreadId();
+    EXPECT_NE(previous_id, current_id);
+    previous_id = current_id;
+    a.Stop();
+  }
+}
+
+// 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_FALSE(a.task_runner());
+}
+
+TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) {
+  Thread a("MultipleWaitUntilThreadStarted");
+  EXPECT_TRUE(a.Start());
+  // It's OK to call WaitUntilThreadStarted() multiple times.
+  EXPECT_TRUE(a.WaitUntilThreadStarted());
+  EXPECT_TRUE(a.WaitUntilThreadStarted());
+}
diff --git a/libchrome/base/threading/worker_pool.cc b/libchrome/base/threading/worker_pool.cc
new file mode 100644
index 0000000..0b7bf8e
--- /dev/null
+++ b/libchrome/base/threading/worker_pool.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.
+
+#include "base/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/macros.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) {
+  }
+  ~PostTaskAndReplyWorkerPool() override = default;
+
+ 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
+  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/libchrome/base/threading/worker_pool.h b/libchrome/base/threading/worker_pool.h
new file mode 100644
index 0000000..a52a414
--- /dev/null
+++ b/libchrome/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/libchrome/base/threading/worker_pool_posix.cc b/libchrome/base/threading/worker_pool_posix.cc
new file mode 100644
index 0000000..6b4c42f
--- /dev/null
+++ b/libchrome/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 <stddef.h>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.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_TASK_EXECUTION("WorkerThread::ThreadMain::Run", pending_task);
+
+    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(std::move(*pending_task));
+
+  // 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 = std::move(pending_tasks_.front());
+  pending_tasks_.pop();
+  return pending_task;
+}
+
+}  // namespace base
diff --git a/libchrome/base/threading/worker_pool_posix.h b/libchrome/base/threading/worker_pool_posix.h
new file mode 100644
index 0000000..628e2b6
--- /dev/null
+++ b/libchrome/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 <memory>
+#include <queue>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.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.
+  std::unique_ptr<ConditionVariable> num_idle_threads_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WORKER_POOL_POSIX_H_
diff --git a/libchrome/base/threading/worker_pool_posix_unittest.cc b/libchrome/base/threading/worker_pool_posix_unittest.cc
new file mode 100644
index 0000000..6cefeed
--- /dev/null
+++ b/libchrome/base/threading/worker_pool_posix_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/threading/worker_pool_posix.h"
+
+#include <set>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.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_(WaitableEvent::ResetPolicy::MANUAL,
+               WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+  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/libchrome/base/threading/worker_pool_unittest.cc b/libchrome/base/threading/worker_pool_unittest.cc
new file mode 100644
index 0000000..ef4bed1
--- /dev/null
+++ b/libchrome/base/threading/worker_pool_unittest.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/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 "build/build_config.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_(WaitableEvent::ResetPolicy::AUTOMATIC,
+                    WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                           WaitableEvent::InitialState::NOT_SIGNALED);
+  WaitableEvent long_test_event(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                WaitableEvent::InitialState::NOT_SIGNALED);
+
+  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/libchrome/base/time/clock.cc b/libchrome/base/time/clock.cc
new file mode 100644
index 0000000..34dc37e
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/clock.h b/libchrome/base/time/clock.h
new file mode 100644
index 0000000..507a850
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/default_clock.cc b/libchrome/base/time/default_clock.cc
new file mode 100644
index 0000000..5f70114
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/default_clock.h b/libchrome/base/time/default_clock.h
new file mode 100644
index 0000000..0b8250e
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/default_tick_clock.cc b/libchrome/base/time/default_tick_clock.cc
new file mode 100644
index 0000000..ce62fcc
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/default_tick_clock.h b/libchrome/base/time/default_tick_clock.h
new file mode 100644
index 0000000..cb041e6
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/pr_time_unittest.cc b/libchrome/base/time/pr_time_unittest.cc
new file mode 100644
index 0000000..3f1a348
--- /dev/null
+++ b/libchrome/base/time/pr_time_unittest.cc
@@ -0,0 +1,290 @@
+// Copyright (c) 2012 The Chromium Authors. 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/macros.h"
+#include "base/third_party/nspr/prtime.h"
+#include "base/time/time.h"
+#include "build/build_config.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/libchrome/base/time/tick_clock.cc b/libchrome/base/time/tick_clock.cc
new file mode 100644
index 0000000..495805c
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/tick_clock.h b/libchrome/base/time/tick_clock.h
new file mode 100644
index 0000000..f7aba53
--- /dev/null
+++ b/libchrome/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/libchrome/base/time/time.cc b/libchrome/base/time/time.cc
new file mode 100644
index 0000000..3670f55
--- /dev/null
+++ b/libchrome/base/time/time.cc
@@ -0,0 +1,350 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/nspr/prtime.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// TimeDelta ------------------------------------------------------------------
+
+// static
+TimeDelta TimeDelta::Max() {
+  return TimeDelta(std::numeric_limits<int64_t>::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_t TimeDelta::InSeconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64_t>::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_t TimeDelta::InMilliseconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64_t>::max();
+  }
+  return delta_ / Time::kMicrosecondsPerMillisecond;
+}
+
+int64_t TimeDelta::InMillisecondsRoundedUp() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64_t>::max();
+  }
+  return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
+      Time::kMicrosecondsPerMillisecond;
+}
+
+int64_t TimeDelta::InMicroseconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64_t>::max();
+  }
+  return delta_;
+}
+
+namespace time_internal {
+
+int64_t SaturatedAdd(TimeDelta delta, int64_t value) {
+  CheckedNumeric<int64_t> rv(delta.delta_);
+  rv += value;
+  return FromCheckedNumeric(rv);
+}
+
+int64_t SaturatedSub(TimeDelta delta, int64_t value) {
+  CheckedNumeric<int64_t> rv(delta.delta_);
+  rv -= value;
+  return FromCheckedNumeric(rv);
+}
+
+int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> 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_t limit = std::numeric_limits<int64_t>::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::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(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt);
+}
+
+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_t>::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.
+  return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt);
+}
+
+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.
+  return Time(kTimeTToMicrosecondsOffset) +
+         TimeDelta::FromMillisecondsD(ms_since_epoch);
+}
+
+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_t 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_t>::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;
+}
+
+// static
+bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) {
+  return lhs.year == rhs.year && lhs.month == rhs.month &&
+         lhs.day_of_month == rhs.day_of_month && lhs.hour == rhs.hour &&
+         lhs.minute == rhs.minute && lhs.second == rhs.second &&
+         lhs.millisecond == rhs.millisecond;
+}
+
+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";
+}
+
+// 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/libchrome/base/time/time.h b/libchrome/base/time/time.h
new file mode 100644
index 0000000..efece96
--- /dev/null
+++ b/libchrome/base/time/time.h
@@ -0,0 +1,832 @@
+// Copyright (c) 2012 The Chromium 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 and ThreadTicks 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.
+
+#ifndef BASE_TIME_TIME_H_
+#define BASE_TIME_TIME_H_
+
+#include <stdint.h>
+#include <time.h>
+
+#include <iosfwd>
+#include <limits>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.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>
+#include "base/gtest_prod_util.h"
+#endif
+
+namespace base {
+
+class PlatformThreadHandle;
+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_t argument and return
+// value are in terms of a microsecond timebase.
+BASE_EXPORT int64_t SaturatedAdd(TimeDelta delta, int64_t value);
+BASE_EXPORT int64_t SaturatedSub(TimeDelta delta, int64_t value);
+
+// Clamp |value| on overflow and underflow conditions. The int64_t argument and
+// return value are in terms of a microsecond timebase.
+BASE_EXPORT int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> value);
+
+}  // namespace time_internal
+
+// TimeDelta ------------------------------------------------------------------
+
+class BASE_EXPORT TimeDelta {
+ public:
+  TimeDelta() : delta_(0) {
+  }
+
+  // Converts units of time to TimeDeltas.
+  static constexpr TimeDelta FromDays(int days);
+  static constexpr TimeDelta FromHours(int hours);
+  static constexpr TimeDelta FromMinutes(int minutes);
+  static constexpr TimeDelta FromSeconds(int64_t secs);
+  static constexpr TimeDelta FromMilliseconds(int64_t ms);
+  static constexpr TimeDelta FromSecondsD(double secs);
+  static constexpr TimeDelta FromMillisecondsD(double ms);
+  static constexpr TimeDelta FromMicroseconds(int64_t 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_t 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_t 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_t overload for std::abs().  The following is a simple branchless
+    // implementation:
+    const int64_t 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_t>::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_t InSeconds() const;
+  double InMillisecondsF() const;
+  int64_t InMilliseconds() const;
+  int64_t InMillisecondsRoundedUp() const;
+  int64_t 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_t> rv(delta_);
+    rv *= a;
+    return TimeDelta(time_internal::FromCheckedNumeric(rv));
+  }
+  template<typename T>
+  TimeDelta operator/(T a) const {
+    CheckedNumeric<int64_t> 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_t operator/(TimeDelta a) const { return delta_ / a.delta_; }
+  TimeDelta operator%(TimeDelta a) const {
+    return TimeDelta(delta_ % a.delta_);
+  }
+
+  // Comparison operators.
+  constexpr bool operator==(TimeDelta other) const {
+    return delta_ == other.delta_;
+  }
+  constexpr bool operator!=(TimeDelta other) const {
+    return delta_ != other.delta_;
+  }
+  constexpr bool operator<(TimeDelta other) const {
+    return delta_ < other.delta_;
+  }
+  constexpr bool operator<=(TimeDelta other) const {
+    return delta_ <= other.delta_;
+  }
+  constexpr bool operator>(TimeDelta other) const {
+    return delta_ > other.delta_;
+  }
+  constexpr bool operator>=(TimeDelta other) const {
+    return delta_ >= other.delta_;
+  }
+
+ private:
+  friend int64_t time_internal::SaturatedAdd(TimeDelta delta, int64_t value);
+  friend int64_t time_internal::SaturatedSub(TimeDelta delta, int64_t 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.
+  constexpr explicit TimeDelta(int64_t delta_us) : delta_(delta_us) {}
+
+  // Private method to build a delta from a double.
+  static constexpr TimeDelta FromDouble(double value);
+
+  // Private method to build a delta from the product of a user-provided value
+  // and a known-positive value.
+  static constexpr TimeDelta FromProduct(int64_t value, int64_t positive_value);
+
+  // Delta in microseconds.
+  int64_t 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_t kHoursPerDay = 24;
+  static const int64_t kMillisecondsPerSecond = 1000;
+  static const int64_t kMillisecondsPerDay =
+      kMillisecondsPerSecond * 60 * 60 * kHoursPerDay;
+  static const int64_t kMicrosecondsPerMillisecond = 1000;
+  static const int64_t kMicrosecondsPerSecond =
+      kMicrosecondsPerMillisecond * kMillisecondsPerSecond;
+  static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+  static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+  static const int64_t kMicrosecondsPerDay =
+      kMicrosecondsPerHour * kHoursPerDay;
+  static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+  static const int64_t kNanosecondsPerMicrosecond = 1000;
+  static const int64_t 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_t>::max(); }
+
+  // Returns the maximum time, which should be greater than any reasonable time
+  // with which we might compare it.
+  static TimeClass Max() {
+    return TimeClass(std::numeric_limits<int64_t>::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_t 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_t us) { return TimeClass(us); }
+
+ protected:
+  explicit TimeBase(int64_t us) : us_(us) {}
+
+  // Time value in a microsecond timebase.
+  int64_t 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_t 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_t 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.
+  enum : int64_t{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 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_t 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.
+  // TODO(maksims): Get rid of these in favor of the methods below when
+  // all the callers stop using these ones.
+  static Time FromUTCExploded(const Exploded& exploded) {
+    base::Time time;
+    ignore_result(FromUTCExploded(exploded, &time));
+    return time;
+  }
+  static Time FromLocalExploded(const Exploded& exploded) {
+    base::Time time;
+    ignore_result(FromLocalExploded(exploded, &time));
+    return time;
+  }
+
+  // Converts an exploded structure representing either the local time or UTC
+  // into a Time class. Returns false on a failure when, for example, a day of
+  // month is set to 31 on a 28-30 day month.
+  static bool FromUTCExploded(const Exploded& exploded,
+                              Time* time) WARN_UNUSED_RESULT {
+    return FromExploded(false, exploded, time);
+  }
+  static bool FromLocalExploded(const Exploded& exploded,
+                                Time* time) WARN_UNUSED_RESULT {
+    return FromExploded(true, exploded, time);
+  }
+
+  // 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_t 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|. Function returns false on
+  // failure and sets |time| to Time(0). Otherwise returns true and sets |time|
+  // to non-exploded time.
+  static bool FromExploded(bool is_local,
+                           const Exploded& exploded,
+                           Time* time) WARN_UNUSED_RESULT;
+
+  // 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);
+
+  // Comparison does not consider |day_of_week| when doing the operation.
+  static bool ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs);
+};
+
+// static
+constexpr TimeDelta TimeDelta::FromDays(int days) {
+  return days == std::numeric_limits<int>::max()
+             ? Max()
+             : TimeDelta(days * Time::kMicrosecondsPerDay);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromHours(int hours) {
+  return hours == std::numeric_limits<int>::max()
+             ? Max()
+             : TimeDelta(hours * Time::kMicrosecondsPerHour);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMinutes(int minutes) {
+  return minutes == std::numeric_limits<int>::max()
+             ? Max()
+             : TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromSeconds(int64_t secs) {
+  return FromProduct(secs, Time::kMicrosecondsPerSecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMilliseconds(int64_t ms) {
+  return FromProduct(ms, Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromSecondsD(double secs) {
+  return FromDouble(secs * Time::kMicrosecondsPerSecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMillisecondsD(double ms) {
+  return FromDouble(ms * Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMicroseconds(int64_t us) {
+  return TimeDelta(us);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromDouble(double value) {
+  // TODO(crbug.com/612601): Use saturated_cast<int64_t>(value) once we sort out
+  // the Min() behavior.
+  return value > std::numeric_limits<int64_t>::max()
+             ? Max()
+             : value < -std::numeric_limits<int64_t>::max()
+                   ? -Max()
+                   : TimeDelta(static_cast<int64_t>(value));
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromProduct(int64_t value,
+                                           int64_t positive_value) {
+  return (
+#if !defined(_PREFAST_) || !defined(OS_WIN)
+          // Avoid internal compiler errors in /analyze builds with VS 2015
+          // update 3.
+          // https://connect.microsoft.com/VisualStudio/feedback/details/2870865
+          DCHECK(positive_value > 0),
+#endif
+          value > std::numeric_limits<int64_t>::max() / positive_value
+              ? Max()
+              : value < -std::numeric_limits<int64_t>::max() / positive_value
+                    ? -Max()
+                    : TimeDelta(value * positive_value));
+}
+
+// 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:
+  // The underlying clock used to generate new TimeTicks.
+  enum class Clock {
+    LINUX_CLOCK_MONOTONIC,
+    IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME,
+    MAC_MACH_ABSOLUTE_TIME,
+    WIN_QPC,
+    WIN_ROLLOVER_PROTECTED_TIME_GET_TIME
+  };
+
+  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 an estimate of the TimeTick value at the time of the UnixEpoch. Because
+  // Time and TimeTicks respond differently to user-set time and NTP
+  // adjustments, this number is only an estimate. Nevertheless, this can be
+  // 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;
+
+  // Returns an enum indicating the underlying clock being used to generate
+  // TimeTicks timestamps. This function should only be used for debugging and
+  // logging purposes.
+  static Clock GetClock();
+
+#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_t 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;
+#elif defined(OS_WIN)
+    return IsSupportedWin();
+#else
+    return false;
+#endif
+  }
+
+  // Waits until the initialization is completed. Needs to be guarded with a
+  // call to IsSupported().
+  static void WaitUntilInitialized() {
+#if defined(OS_WIN)
+    WaitUntilInitializedWin();
+#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. Returns an empty ThreadTicks
+  // object until the initialization is completed. If a clock reading is
+  // absolutely needed, call WaitUntilInitialized() before this method.
+  static ThreadTicks Now();
+
+#if defined(OS_WIN)
+  // Similar to Now() above except this returns thread-specific CPU time for an
+  // arbitrary thread. All comments for Now() method above apply apply to this
+  // method as well.
+  static ThreadTicks GetForThread(const PlatformThreadHandle& thread_handle);
+#endif
+
+ private:
+  friend class time_internal::TimeBase<ThreadTicks>;
+
+  // Please use Now() or GetForThread() to create a new object. This is for
+  // internal use and testing.
+  explicit ThreadTicks(int64_t us) : TimeBase(us) {}
+
+#if defined(OS_WIN)
+  FRIEND_TEST_ALL_PREFIXES(TimeTicks, TSCTicksPerSecond);
+
+  // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't
+  // been measured yet. Needs to be guarded with a call to IsSupported().
+  // This method is declared here rather than in the anonymous namespace to
+  // allow testing.
+  static double TSCTicksPerSecond();
+
+  static bool IsSupportedWin();
+  static void WaitUntilInitializedWin();
+#endif
+};
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
+
+}  // namespace base
+
+#endif  // BASE_TIME_TIME_H_
diff --git a/libchrome/base/time/time_mac.cc b/libchrome/base/time/time_mac.cc
new file mode 100644
index 0000000..373ec3a
--- /dev/null
+++ b/libchrome/base/time/time_mac.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/time/time.h"
+
+#include <CoreFoundation/CFDate.h>
+#include <CoreFoundation/CFTimeZone.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.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/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "build/build_config.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, nullptr, 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.get(),
+      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 +
+      thread_info_data.system_time.seconds);
+  absolute_micros *= base::Time::kMicrosecondsPerSecond;
+  absolute_micros += (thread_info_data.user_time.microseconds +
+                      thread_info_data.system_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_t kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+
+// static
+const int64_t 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_t Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+
+// static
+Time Time::Now() {
+  return FromCFAbsoluteTime(CFAbsoluteTimeGetCurrent());
+}
+
+// static
+Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
+  static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                "CFAbsoluteTime must have an infinity value");
+  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>((t + kCFAbsoluteTimeIntervalSince1970) *
+                                   kMicrosecondsPerSecond) +
+              kWindowsEpochDeltaMicroseconds);
+}
+
+CFAbsoluteTime Time::ToCFAbsoluteTime() const {
+  static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                "CFAbsoluteTime must have an infinity value");
+  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
+bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
+  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
+      is_local
+          ? CFTimeZoneCopySystem()
+          : CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0));
+  base::ScopedCFTypeRef<CFCalendarRef> gregorian(CFCalendarCreateWithIdentifier(
+      kCFAllocatorDefault, kCFGregorianCalendar));
+  CFCalendarSetTimeZone(gregorian, time_zone);
+  CFAbsoluteTime absolute_time;
+  // 'S' is not defined in componentDesc in Apple documentation, but can be
+  // found at http://www.opensource.apple.com/source/CF/CF-855.17/CFCalendar.c
+  CFCalendarComposeAbsoluteTime(
+      gregorian, &absolute_time, "yMdHmsS", exploded.year, exploded.month,
+      exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
+      exploded.millisecond);
+  CFAbsoluteTime seconds = absolute_time + kCFAbsoluteTimeIntervalSince1970;
+
+  base::Time converted_time =
+      Time(static_cast<int64_t>(seconds * kMicrosecondsPerSecond) +
+           kWindowsEpochDeltaMicroseconds);
+
+  // If |exploded.day_of_month| is set to 31
+  // on a 28-30 day month, it will return the first day of the next month.
+  // Thus round-trip the time and compare the initial |exploded| with
+  // |utc_to_exploded| time.
+  base::Time::Exploded to_exploded;
+  if (!is_local)
+    converted_time.UTCExplode(&to_exploded);
+  else
+    converted_time.LocalExplode(&to_exploded);
+
+  if (ExplodedMostlyEquals(to_exploded, exploded)) {
+    *time = converted_time;
+    return true;
+  }
+
+  *time = Time(0);
+  return false;
+}
+
+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_t microsecond = us_ % kMicrosecondsPerSecond;
+  if (microsecond < 0)
+    microsecond += kMicrosecondsPerSecond;
+  CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
+                           kWindowsEpochDeltaSeconds -
+                           kCFAbsoluteTimeIntervalSince1970;
+
+  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
+      is_local
+          ? CFTimeZoneCopySystem()
+          : CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, 0));
+  base::ScopedCFTypeRef<CFCalendarRef> gregorian(CFCalendarCreateWithIdentifier(
+      kCFAllocatorDefault, kCFGregorianCalendar));
+  CFCalendarSetTimeZone(gregorian, time_zone);
+  int second, day_of_week;
+  // 'E' sets the day of week, but is not defined in componentDesc in Apple
+  // documentation. It can be found in open source code here:
+  // http://www.opensource.apple.com/source/CF/CF-855.17/CFCalendar.c
+  CFCalendarDecomposeAbsoluteTime(gregorian, seconds, "yMdHmsE",
+                                  &exploded->year, &exploded->month,
+                                  &exploded->day_of_month, &exploded->hour,
+                                  &exploded->minute, &second, &day_of_week);
+  // Make sure seconds are rounded down towards -infinity.
+  exploded->second = floor(second);
+  // |Exploded|'s convention for day of week is 0 = Sunday, i.e. different
+  // from CF's 1 = Sunday.
+  exploded->day_of_week = (day_of_week - 1) % 7;
+  // 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
+TimeTicks::Clock TimeTicks::GetClock() {
+#if defined(OS_IOS)
+  return Clock::IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME;
+#else
+  return Clock::MAC_MACH_ABSOLUTE_TIME;
+#endif  // defined(OS_IOS)
+}
+
+// static
+ThreadTicks ThreadTicks::Now() {
+  return ThreadTicks(ComputeThreadTicks());
+}
+
+}  // namespace base
diff --git a/libchrome/base/time/time_posix.cc b/libchrome/base/time/time_posix.cc
new file mode 100644
index 0000000..495e249
--- /dev/null
+++ b/libchrome/base/time/time_posix.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/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_t ConvertTimespecToMicros(const struct timespec& ts) {
+  base::CheckedNumeric<int64_t> 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_t 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_t 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_t kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+
+// static
+const int64_t 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_t 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_t microseconds = us_ - kWindowsEpochDeltaMicroseconds;
+  // The following values are all rounded towards -infinity.
+  int64_t 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
+bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
+  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_t 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_t seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+    timestruct = timestruct0;
+    timestruct.tm_isdst = 1;
+    int64_t 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_t, special care must be taken to avoid
+    // overflows.
+    const int64_t min_seconds = (sizeof(SysTime) < sizeof(int64_t))
+                                    ? std::numeric_limits<SysTime>::min()
+                                    : std::numeric_limits<int32_t>::min();
+    const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t))
+                                    ? 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.
+  base::Time converted_time =
+      Time((milliseconds * kMicrosecondsPerMillisecond) +
+           kWindowsEpochDeltaMicroseconds);
+
+  // If |exploded.day_of_month| is set to 31 on a 28-30 day month, it will
+  // return the first day of the next month. Thus round-trip the time and
+  // compare the initial |exploded| with |utc_to_exploded| time.
+  base::Time::Exploded to_exploded;
+  if (!is_local)
+    converted_time.UTCExplode(&to_exploded);
+  else
+    converted_time.LocalExplode(&to_exploded);
+
+  if (ExplodedMostlyEquals(to_exploded, exploded)) {
+    *time = converted_time;
+    return true;
+  }
+
+  *time = Time(0);
+  return false;
+}
+
+// TimeTicks ------------------------------------------------------------------
+// static
+TimeTicks TimeTicks::Now() {
+  return TimeTicks(ClockNow(CLOCK_MONOTONIC));
+}
+
+// static
+TimeTicks::Clock TimeTicks::GetClock() {
+  return Clock::LINUX_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
+}
+
+#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>(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_t us = us_ - kTimeTToMicrosecondsOffset;
+  result.tv_sec = us / Time::kMicrosecondsPerSecond;
+  result.tv_usec = us % Time::kMicrosecondsPerSecond;
+  return result;
+}
+
+}  // namespace base
diff --git a/libchrome/base/time/time_unittest.cc b/libchrome/base/time/time_unittest.cc
new file mode 100644
index 0000000..4f47d56
--- /dev/null
+++ b/libchrome/base/time/time_unittest.cc
@@ -0,0 +1,1182 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/macros.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 {
+
+TEST(TimeTestOutOfBounds, FromExplodedOutOfBoundsTime) {
+  // FromUTCExploded must set time to Time(0) and failure, if the day is set to
+  // 31 on a 28-30 day month. Test |exploded| returns Time(0) on 31st of
+  // February and 31st of April. New implementation handles this.
+
+  const struct DateTestData {
+    Time::Exploded explode;
+    bool is_valid;
+  } kDateTestData[] = {
+      // 31st of February
+      {{2016, 2, 0, 31, 12, 30, 0, 0}, true},
+      // 31st of April
+      {{2016, 4, 0, 31, 8, 43, 0, 0}, true},
+      // Negative month
+      {{2016, -5, 0, 2, 4, 10, 0, 0}, false},
+      // Negative date of month
+      {{2016, 6, 0, -15, 2, 50, 0, 0}, false},
+      // Negative hours
+      {{2016, 7, 0, 10, -11, 29, 0, 0}, false},
+      // Negative minutes
+      {{2016, 3, 0, 14, 10, -29, 0, 0}, false},
+      // Negative seconds
+      {{2016, 10, 0, 25, 7, 47, -30, 0}, false},
+      // Negative milliseconds
+      {{2016, 10, 0, 25, 7, 47, 20, -500}, false},
+      // Hours are too large
+      {{2016, 7, 0, 10, 26, 29, 0, 0}, false},
+      // Minutes are too large
+      {{2016, 3, 0, 14, 10, 78, 0, 0}, false},
+      // Seconds are too large
+      {{2016, 10, 0, 25, 7, 47, 234, 0}, false},
+      // Milliseconds are too large
+      {{2016, 10, 0, 25, 6, 31, 23, 1643}, false},
+  };
+
+  for (const auto& test : kDateTestData) {
+    EXPECT_EQ(test.explode.HasValidValues(), test.is_valid);
+
+    base::Time result;
+    EXPECT_FALSE(base::Time::FromUTCExploded(test.explode, &result));
+    EXPECT_TRUE(result.is_null());
+    EXPECT_FALSE(base::Time::FromLocalExploded(test.explode, &result));
+    EXPECT_TRUE(result.is_null());
+  }
+}
+
+// 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;
+  EXPECT_TRUE(Time::FromLocalExploded(exploded, &our_time_2));
+  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;
+  EXPECT_TRUE(Time::FromUTCExploded(exploded1, &time));
+  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;
+  EXPECT_TRUE(Time::FromLocalExploded(exploded, &b));
+
+  // 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;
+  EXPECT_TRUE(Time::FromUTCExploded(exploded, &b));
+  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, 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_t>::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_t>::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;
+  EXPECT_TRUE(Time::FromLocalExploded(midnight, &t));
+  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()) {
+    ThreadTicks::WaitUntilInitialized();
+    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(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) {
+  // static_assert also checks that the contained expression is a constant
+  // expression, meaning all its components are suitable for initializing global
+  // variables.
+  static_assert(TimeDelta::FromDays(2) == TimeDelta::FromHours(48), "");
+  static_assert(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180), "");
+  static_assert(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120), "");
+  static_assert(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000),
+                "");
+  static_assert(
+      TimeDelta::FromMilliseconds(2) == TimeDelta::FromMicroseconds(2000), "");
+  static_assert(
+      TimeDelta::FromSecondsD(2.3) == TimeDelta::FromMilliseconds(2300), "");
+  static_assert(
+      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());
+  EXPECT_EQ(3.456, TimeDelta::FromMillisecondsD(3.45678).InMillisecondsF());
+}
+
+#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;
+  EXPECT_TRUE(Time::FromUTCExploded(exploded, &t));
+  // 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_t zero = 0;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(zero),
+            TimeDelta::FromMicroseconds(zero).magnitude());
+
+  const int64_t one = 1;
+  const int64_t negative_one = -1;
+  EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+            TimeDelta::FromMicroseconds(one).magnitude());
+  EXPECT_EQ(TimeDelta::FromMicroseconds(one),
+            TimeDelta::FromMicroseconds(negative_one).magnitude());
+
+  const int64_t max_int64_minus_one = std::numeric_limits<int64_t>::max() - 1;
+  const int64_t min_int64_plus_two = std::numeric_limits<int64_t>::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, Max) {
+  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());
+}
+
+bool IsMin(TimeDelta delta) {
+  return (-delta).is_max();
+}
+
+TEST(TimeDelta, MaxConversions) {
+  TimeDelta t = TimeDelta::Max();
+  EXPECT_EQ(std::numeric_limits<int64_t>::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_t>::max(), t.InSeconds());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF());
+  EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.InMilliseconds());
+  EXPECT_EQ(std::numeric_limits<int64_t>::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());
+
+  int64_t max_int = std::numeric_limits<int64_t>::max();
+
+  t = TimeDelta::FromSeconds(max_int / Time::kMicrosecondsPerSecond + 1);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMilliseconds(max_int / Time::kMillisecondsPerSecond + 1);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMicroseconds(max_int);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSeconds(-max_int / Time::kMicrosecondsPerSecond - 1);
+  EXPECT_TRUE(IsMin(t));
+
+  t = TimeDelta::FromMilliseconds(-max_int / Time::kMillisecondsPerSecond - 1);
+  EXPECT_TRUE(IsMin(t));
+
+  t = TimeDelta::FromMicroseconds(-max_int);
+  EXPECT_TRUE(IsMin(t));
+
+  t = -TimeDelta::FromMicroseconds(std::numeric_limits<int64_t>::min());
+  EXPECT_FALSE(IsMin(t));
+
+  t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  double max_d = max_int;
+
+  t = TimeDelta::FromSecondsD(max_d / Time::kMicrosecondsPerSecond + 1);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMillisecondsD(max_d / Time::kMillisecondsPerSecond * 2);
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSecondsD(-max_d / Time::kMicrosecondsPerSecond - 1);
+  EXPECT_TRUE(IsMin(t));
+
+  t = TimeDelta::FromMillisecondsD(-max_d / Time::kMillisecondsPerSecond * 2);
+  EXPECT_TRUE(IsMin(t));
+}
+
+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));
+}
+
+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/libchrome/base/timer/elapsed_timer.cc b/libchrome/base/timer/elapsed_timer.cc
new file mode 100644
index 0000000..f2a2f71
--- /dev/null
+++ b/libchrome/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/libchrome/base/timer/elapsed_timer.h b/libchrome/base/timer/elapsed_timer.h
new file mode 100644
index 0000000..592858a
--- /dev/null
+++ b/libchrome/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/libchrome/base/timer/hi_res_timer_manager.h b/libchrome/base/timer/hi_res_timer_manager.h
new file mode 100644
index 0000000..21cdfaf
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/timer/hi_res_timer_manager_posix.cc b/libchrome/base/timer/hi_res_timer_manager_posix.cc
new file mode 100644
index 0000000..d2f152c
--- /dev/null
+++ b/libchrome/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/libchrome/base/timer/hi_res_timer_manager_unittest.cc b/libchrome/base/timer/hi_res_timer_manager_unittest.cc
new file mode 100644
index 0000000..a0b0f93
--- /dev/null
+++ b/libchrome/base/timer/hi_res_timer_manager_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/timer/hi_res_timer_manager.h"
+
+#include <memory>
+#include <utility>
+
+#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 "build/build_config.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);
+  std::unique_ptr<base::PowerMonitorSource> power_monitor_source(
+      new base::PowerMonitorDeviceSource());
+  std::unique_ptr<base::PowerMonitor> power_monitor(
+      new base::PowerMonitor(std::move(power_monitor_source)));
+
+  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/libchrome/base/timer/mock_timer.cc b/libchrome/base/timer/mock_timer.cc
new file mode 100644
index 0000000..296071e
--- /dev/null
+++ b/libchrome/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/libchrome/base/timer/mock_timer.h b/libchrome/base/timer/mock_timer.h
new file mode 100644
index 0000000..e18a5c0
--- /dev/null
+++ b/libchrome/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/libchrome/base/timer/mock_timer_unittest.cc b/libchrome/base/timer/mock_timer_unittest.cc
new file mode 100644
index 0000000..a389815
--- /dev/null
+++ b/libchrome/base/timer/mock_timer_unittest.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/timer/mock_timer.h"
+
+#include "base/macros.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/libchrome/base/timer/timer.cc b/libchrome/base/timer/timer.cc
new file mode 100644
index 0000000..e554905
--- /dev/null
+++ b/libchrome/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/threading/platform_thread.h"
+#include "base/threading/thread_task_runner_handle.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/libchrome/base/timer/timer.h b/libchrome/base/timer/timer.h
new file mode 100644
index 0000000..661829b
--- /dev/null
+++ b/libchrome/base/timer/timer.h
@@ -0,0 +1,279 @@
+// Copyright (c) 2012 The Chromium 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 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/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/macros.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.
+class BaseTimerMethodPointer : public Timer {
+ public:
+  // 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;
+
+  enum RepeatMode { ONE_SHOT, REPEATING };
+  BaseTimerMethodPointer(RepeatMode mode)
+      : Timer(mode == REPEATING, mode == REPEATING) {}
+
+  // 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|.
+  template <class Receiver>
+  void Start(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             Receiver* receiver,
+             void (Receiver::*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.
+class OneShotTimer : public BaseTimerMethodPointer {
+ public:
+  OneShotTimer() : BaseTimerMethodPointer(ONE_SHOT) {}
+};
+
+//-----------------------------------------------------------------------------
+// A simple, repeating timer.  See usage notes at the top of the file.
+class RepeatingTimer : public BaseTimerMethodPointer {
+ public:
+  RepeatingTimer() : BaseTimerMethodPointer(REPEATING) {}
+};
+
+//-----------------------------------------------------------------------------
+// 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.
+class DelayTimer : protected Timer {
+ public:
+  template <class Receiver>
+  DelayTimer(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             Receiver* receiver,
+             void (Receiver::*method)())
+      : Timer(posted_from,
+              delay,
+              base::Bind(method, base::Unretained(receiver)),
+              false) {}
+
+  void Reset() override;
+};
+
+// This class has a templated method so it can not be exported without failing
+// to link in MSVC. But clang-plugin does not allow inline definitions of
+// virtual methods, so the inline definition lives in the header file here
+// to satisfy both.
+inline void DelayTimer::Reset() {
+  Timer::Reset();
+}
+
+}  // namespace base
+
+#endif  // BASE_TIMER_TIMER_H_
diff --git a/libchrome/base/timer/timer_unittest.cc b/libchrome/base/timer/timer_unittest.cc
new file mode 100644
index 0000000..6fcd25b
--- /dev/null
+++ b/libchrome/base/timer/timer_unittest.cc
@@ -0,0 +1,539 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <memory>
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.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 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()) {}
+
+  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_;
+  std::unique_ptr<base::OneShotTimer> 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 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::RunLoop().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::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  OneShotTimerTester b(&did_run_b);
+  b.Start();
+
+  base::RunLoop().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::RunLoop().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::RunLoop().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::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  RepeatingTimerTester b(&did_run_b, delay);
+  b.Start();
+
+  base::RunLoop().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 timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target,
+                         &DelayTimerTarget::Signal);
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run);
+  tester.Start();
+  base::RunLoop().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 timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target,
+                         &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run, 100 /* milliseconds */);
+  tester.Start();
+  base::RunLoop().Run();
+
+  ASSERT_TRUE(target.signaled());
+}
+
+struct ResetHelper {
+  ResetHelper(base::DelayTimer* timer, DelayTimerTarget* target)
+      : timer_(timer), target_(target) {}
+
+  void Reset() {
+    ASSERT_FALSE(target_->signaled());
+    timer_->Reset();
+  }
+
+ private:
+  base::DelayTimer* 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 timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+                         &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  ResetHelper reset_helper(&timer, &target);
+
+  base::OneShotTimer 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::RunLoop().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 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::RunLoop().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::RunLoop().Run();
+    EXPECT_TRUE(g_callback_happened1);
+  }
+}
+
+}  // namespace
diff --git a/libchrome/base/trace_event/OWNERS b/libchrome/base/trace_event/OWNERS
new file mode 100644
index 0000000..9160267
--- /dev/null
+++ b/libchrome/base/trace_event/OWNERS
@@ -0,0 +1,6 @@
+dsinclair@chromium.org
+nduca@chromium.org
+oysteine@chromium.org
+primiano@chromium.org
+simonhatch@chromium.org
+per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/libchrome/base/trace_event/common/trace_event_common.h b/libchrome/base/trace_event/common/trace_event_common.h
new file mode 100644
index 0000000..0a04d62
--- /dev/null
+++ b/libchrome/base/trace_event/common/trace_event_common.h
@@ -0,0 +1,1093 @@
+// 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 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.
+
+// IMPORTANT: To avoid conflicts, if you need to modify this file for a library,
+// land your change in base/ first, and then copy-and-paste it.
+
+// 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",
+//                std::unique_ptr<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.
+
+#if defined(TRACE_EVENT0)
+#error "Another copy of this file has already been included."
+#endif
+
+// 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
+
+// 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_EVENT_ADD_SCOPED(category_group, name)
+#define TRACE_EVENT_WITH_FLOW0(category_group, name, bind_id, flow_flags)  \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+                                            flow_flags)
+#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val)
+#define TRACE_EVENT_WITH_FLOW1(category_group, name, bind_id, flow_flags,  \
+                               arg1_name, arg1_val)                        \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+                                            flow_flags, arg1_name, arg1_val)
+#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name,   \
+                     arg2_val)                                               \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val, \
+                                  arg2_name, arg2_val)
+#define TRACE_EVENT_WITH_FLOW2(category_group, name, bind_id, flow_flags,    \
+                               arg1_name, arg1_val, arg2_name, arg2_val)     \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id,   \
+                                            flow_flags, 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)
+
+#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \
+                                            timestamp)                   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                    \
+      TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp,  \
+      TRACE_EVENT_FLAG_NONE | scope)
+
+// 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)
+#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(categoryAndName) \
+  TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(0, categoryAndName)
+
+// 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)
+
+#define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \
+                                         arg1_name, arg1_val)             \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp,      \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_COPY_MARK(category_group, name)                      \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY)
+
+#define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp,          \
+      TRACE_EVENT_FLAG_COPY)
+
+// 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))
+
+// Similar to TRACE_COUNTERx, but with a custom |timestamp| provided.
+#define TRACE_COUNTER_WITH_TIMESTAMP1(category_group, name, timestamp, value) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                    \
+      TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp,             \
+      TRACE_EVENT_FLAG_NONE, "value", static_cast<int>(value))
+
+#define TRACE_COUNTER_WITH_TIMESTAMP2(category_group, name, timestamp,      \
+                                      value1_name, value1_val, value2_name, \
+                                      value2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                  \
+      TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp,           \
+      TRACE_EVENT_FLAG_NONE, 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,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(                           \
+    category_group, name, id, timestamp, arg1_name, arg1_val)              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                      \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,             \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+      arg1_name, arg1_val)
+#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,                 \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, 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,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, 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,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1(category_group, name, id,       \
+                                              timestamp, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,    \
+      arg1_name, arg1_val)
+
+// 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)
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 1
+// associated argument. If the category is not enabled, then this does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \
+                                        arg1_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)
+#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)
+
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with one associated argument. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(category_group, name, id,        \
+                                            arg1_name, arg1_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)
+// 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)
+
+#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,        \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, 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,        \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_COPY_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, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_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, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+
+// 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)
+
+// Special trace event macro to trace task execution with the location where it
+// was posted from.
+#define TRACE_TASK_EXECUTION(run_function, task) \
+  INTERNAL_TRACE_TASK_EXECUTION(run_function, task)
+
+// TRACE_EVENT_METADATA* events are information related to other
+// injected events, not events in their own right.
+#define TRACE_EVENT_METADATA1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_METADATA_ADD(category_group, name, arg1_name, arg1_val)
+
+// Records a clock sync event.
+#define TRACE_EVENT_CLOCK_SYNC_RECEIVER(sync_id)                               \
+  INTERNAL_TRACE_EVENT_ADD(                                                    \
+      TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync",                \
+      TRACE_EVENT_FLAG_NONE, "sync_id", sync_id)
+#define TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts)         \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                     \
+      TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync",                \
+      issue_end_ts.ToInternalValue(), TRACE_EVENT_FLAG_NONE,                   \
+      "sync_id", sync_id, "issue_ts", issue_ts.ToInternalValue())
+
+// 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_SNAPSHOT_WITH_ID_AND_TIMESTAMP(                    \
+    category_group, name, id, timestamp, snapshot)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name,                \
+      TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, \
+      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)
+
+// Records entering and leaving trace event contexts. |category_group| and
+// |name| specify the context category and type. |context| is a
+// snapshotted context object id.
+#define TRACE_EVENT_ENTER_CONTEXT(category_group, name, context) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                              \
+      TRACE_EVENT_PHASE_ENTER_CONTEXT, category_group, name,     \
+      TRACE_ID_DONT_MANGLE(context), TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_LEAVE_CONTEXT(category_group, name, context) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                              \
+      TRACE_EVENT_PHASE_LEAVE_CONTEXT, category_group, name,     \
+      TRACE_ID_DONT_MANGLE(context), TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_SCOPED_CONTEXT(category_group, name, context) \
+  INTERNAL_TRACE_EVENT_SCOPED_CONTEXT(category_group, name,       \
+                                      TRACE_ID_DONT_MANGLE(context))
+
+// 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 explicitly warm up a given category group. This could be useful in
+// cases where we want to initialize a category group before any trace events
+// for that category group is reported. For example, to have a category group
+// always show up in the "record categories" list for manually selecting
+// settings in about://tracing.
+#define TRACE_EVENT_WARMUP_CATEGORY(category_group) \
+  INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group)
+
+// 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)
+
+// 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')
+#define TRACE_EVENT_PHASE_MARK ('R')
+#define TRACE_EVENT_PHASE_CLOCK_SYNC ('c')
+#define TRACE_EVENT_PHASE_ENTER_CONTEXT ('(')
+#define TRACE_EVENT_PHASE_LEAVE_CONTEXT (')')
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned int>(0))
+#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned int>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned int>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned int>(1 << 2))
+#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned int>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned int>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned int>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS (static_cast<unsigned int>(1 << 6))
+#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast<unsigned int>(1 << 7))
+#define TRACE_EVENT_FLAG_FLOW_IN (static_cast<unsigned int>(1 << 8))
+#define TRACE_EVENT_FLAG_FLOW_OUT (static_cast<unsigned int>(1 << 9))
+#define TRACE_EVENT_FLAG_HAS_CONTEXT_ID (static_cast<unsigned int>(1 << 10))
+#define TRACE_EVENT_FLAG_HAS_PROCESS_ID (static_cast<unsigned int>(1 << 11))
+
+#define TRACE_EVENT_FLAG_SCOPE_MASK                          \
+  (static_cast<unsigned int>(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')
diff --git a/libchrome/base/trace_event/etw_manifest/BUILD.gn b/libchrome/base/trace_event/etw_manifest/BUILD.gn
new file mode 100644
index 0000000..19c4ecf
--- /dev/null
+++ b/libchrome/base/trace_event/etw_manifest/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/win/message_compiler.gni")
+
+assert(is_win, "This only runs on Windows.")
+
+message_compiler("chrome_events_win") {
+  visibility = [
+    "//base/*",
+    "//chrome:main_dll",
+  ]
+
+  sources = [
+    "chrome_events_win.man",
+  ]
+
+  user_mode_logging = true
+
+  # The only code generated from chrome_events_win.man is a header file that
+  # is included by trace_event_etw_export_win.cc, so there is no need to
+  # compile any generated code. The other thing which compile_generated_code
+  # controls in this context is linking in the .res file generated from the
+  # manifest. However this is only needed for ETW provider registration which
+  # is done by UIforETW (https://github.com/google/UIforETW) and therefore the
+  # manifest resource can be skipped in Chrome.
+  compile_generated_code = false
+}
diff --git a/libchrome/base/trace_event/etw_manifest/chrome_events_win.man b/libchrome/base/trace_event/etw_manifest/chrome_events_win.man
new file mode 100644
index 0000000..10a8ddf
--- /dev/null
+++ b/libchrome/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/libchrome/base/trace_event/etw_manifest/etw_manifest.gyp b/libchrome/base/trace_event/etw_manifest/etw_manifest.gyp
new file mode 100644
index 0000000..b2f0eb8
--- /dev/null
+++ b/libchrome/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/libchrome/base/trace_event/heap_profiler.h b/libchrome/base/trace_event/heap_profiler.h
new file mode 100644
index 0000000..cf57524
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler.h
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All 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_HEAP_PROFILER_H
+#define BASE_TRACE_EVENT_HEAP_PROFILER_H
+
+#include "base/compiler_specific.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+// This header file defines the set of macros that are used to track memory
+// usage in the heap profiler. This is in addition to the macros defined in
+// trace_event.h and are specific to heap profiler. This file also defines
+// implementation details of these macros.
+
+// Implementation detail: heap profiler 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_HEAP_PROFILER_UID3(a, b) heap_profiler_unique_##a##b
+#define INTERNAL_HEAP_PROFILER_UID2(a, b) INTERNAL_HEAP_PROFILER_UID3(a, b)
+#define INTERNAL_HEAP_PROFILER_UID(name_prefix) \
+  INTERNAL_HEAP_PROFILER_UID2(name_prefix, __LINE__)
+
+// Scoped tracker for task execution context in the heap profiler.
+#define TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION \
+  trace_event_internal::HeapProfilerScopedTaskExecutionTracker
+
+// A scoped ignore event used to tell heap profiler to ignore all the
+// allocations in the scope. It is useful to exclude allocations made for
+// tracing from the heap profiler dumps.
+#define HEAP_PROFILER_SCOPED_IGNORE                                          \
+  trace_event_internal::HeapProfilerScopedIgnore INTERNAL_HEAP_PROFILER_UID( \
+      scoped_ignore)
+
+namespace trace_event_internal {
+
+// HeapProfilerScopedTaskExecutionTracker records the current task's context in
+// the heap profiler.
+class HeapProfilerScopedTaskExecutionTracker {
+ public:
+  inline explicit HeapProfilerScopedTaskExecutionTracker(
+      const char* task_context)
+      : context_(task_context) {
+    using base::trace_event::AllocationContextTracker;
+    if (UNLIKELY(AllocationContextTracker::capture_mode() !=
+                 AllocationContextTracker::CaptureMode::DISABLED)) {
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->PushCurrentTaskContext(context_);
+    }
+  }
+
+  inline ~HeapProfilerScopedTaskExecutionTracker() {
+    using base::trace_event::AllocationContextTracker;
+    if (UNLIKELY(AllocationContextTracker::capture_mode() !=
+                 AllocationContextTracker::CaptureMode::DISABLED)) {
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->PopCurrentTaskContext(context_);
+    }
+  }
+
+ private:
+  const char* context_;
+};
+
+class BASE_EXPORT HeapProfilerScopedIgnore {
+ public:
+  inline HeapProfilerScopedIgnore() {
+    using base::trace_event::AllocationContextTracker;
+    if (UNLIKELY(
+            AllocationContextTracker::capture_mode() !=
+            AllocationContextTracker::CaptureMode::DISABLED)) {
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->begin_ignore_scope();
+    }
+  }
+  inline ~HeapProfilerScopedIgnore() {
+    using base::trace_event::AllocationContextTracker;
+    if (UNLIKELY(
+            AllocationContextTracker::capture_mode() !=
+            AllocationContextTracker::CaptureMode::DISABLED)) {
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->end_ignore_scope();
+    }
+  }
+};
+
+}  // namespace trace_event_internal
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_H
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_context.cc b/libchrome/base/trace_event/heap_profiler_allocation_context.cc
new file mode 100644
index 0000000..0f330a8
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_context.cc
@@ -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.
+
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+#include <cstring>
+
+#include "base/hash.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+bool operator < (const StackFrame& lhs, const StackFrame& rhs) {
+  return lhs.value < rhs.value;
+}
+
+bool operator == (const StackFrame& lhs, const StackFrame& rhs) {
+  return lhs.value == rhs.value;
+}
+
+bool operator != (const StackFrame& lhs, const StackFrame& rhs) {
+  return !(lhs.value == rhs.value);
+}
+
+Backtrace::Backtrace(): frame_count(0) {}
+
+bool operator==(const Backtrace& lhs, const Backtrace& rhs) {
+  if (lhs.frame_count != rhs.frame_count) return false;
+  return std::equal(lhs.frames, lhs.frames + lhs.frame_count, rhs.frames);
+}
+
+bool operator!=(const Backtrace& lhs, const Backtrace& rhs) {
+  return !(lhs == rhs);
+}
+
+AllocationContext::AllocationContext(): type_name(nullptr) {}
+
+AllocationContext::AllocationContext(const Backtrace& backtrace,
+                                     const char* type_name)
+  : backtrace(backtrace), type_name(type_name) {}
+
+bool operator==(const AllocationContext& lhs, const AllocationContext& rhs) {
+  return (lhs.backtrace == rhs.backtrace) && (lhs.type_name == rhs.type_name);
+}
+
+bool operator!=(const AllocationContext& lhs, const AllocationContext& rhs) {
+  return !(lhs == rhs);
+}
+}  // namespace trace_event
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+using base::trace_event::AllocationContext;
+using base::trace_event::Backtrace;
+using base::trace_event::StackFrame;
+
+size_t hash<StackFrame>::operator()(const StackFrame& frame) const {
+  return hash<const void*>()(frame.value);
+}
+
+size_t hash<Backtrace>::operator()(const Backtrace& backtrace) const {
+  const void* values[Backtrace::kMaxFrameCount];
+  for (size_t i = 0; i != backtrace.frame_count; ++i) {
+    values[i] = backtrace.frames[i].value;
+  }
+  return base::SuperFastHash(
+      reinterpret_cast<const char*>(values),
+      static_cast<int>(backtrace.frame_count * sizeof(*values)));
+}
+
+size_t hash<AllocationContext>::operator()(const AllocationContext& ctx) const {
+  size_t backtrace_hash = hash<Backtrace>()(ctx.backtrace);
+
+  // Multiplicative hash from [Knuth 1998]. Works best if |size_t| is 32 bits,
+  // because the magic number is a prime very close to 2^32 / golden ratio, but
+  // will still redistribute keys bijectively on 64-bit architectures because
+  // the magic number is coprime to 2^64.
+  size_t type_hash = reinterpret_cast<size_t>(ctx.type_name) * 2654435761;
+
+  // Multiply one side to break the commutativity of +. Multiplication with a
+  // number coprime to |numeric_limits<size_t>::max() + 1| is bijective so
+  // randomness is preserved.
+  return (backtrace_hash * 3) + type_hash;
+}
+
+}  // BASE_HASH_NAMESPACE
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_context.h b/libchrome/base/trace_event/heap_profiler_allocation_context.h
new file mode 100644
index 0000000..24e2dec
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_context.h
@@ -0,0 +1,131 @@
+// 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_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+
+namespace base {
+namespace trace_event {
+
+// When heap profiling is enabled, tracing keeps track of the allocation
+// context for each allocation intercepted. It is generated by the
+// |AllocationContextTracker| which keeps stacks of context in TLS.
+// The tracker is initialized lazily.
+
+// The backtrace in the allocation context is a snapshot of the stack. For now,
+// this is the pseudo stack where frames are created by trace event macros. In
+// the future, we might add the option to use the native call stack. In that
+// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
+// have different implementations that can be selected by a compile time flag.
+
+// The number of stack frames stored in the backtrace is a trade off between
+// memory used for tracing and accuracy. Measurements done on a prototype
+// revealed that:
+//
+// - In 60 percent of the cases, pseudo stack depth <= 7.
+// - In 87 percent of the cases, pseudo stack depth <= 9.
+// - In 95 percent of the cases, pseudo stack depth <= 11.
+//
+// See the design doc (https://goo.gl/4s7v7b) for more details.
+
+// Represents (pseudo) stack frame. Used in Backtrace class below.
+//
+// Conceptually stack frame is identified by its value, and type is used
+// mostly to properly format the value. Value is expected to be a valid
+// pointer from process' address space.
+struct BASE_EXPORT StackFrame {
+  enum class Type {
+    TRACE_EVENT_NAME,   // const char* string
+    THREAD_NAME,        // const char* thread name
+    PROGRAM_COUNTER,    // as returned by stack tracing (e.g. by StackTrace)
+  };
+
+  static StackFrame FromTraceEventName(const char* name) {
+    return {Type::TRACE_EVENT_NAME, name};
+  }
+  static StackFrame FromThreadName(const char* name) {
+    return {Type::THREAD_NAME, name};
+  }
+  static StackFrame FromProgramCounter(const void* pc) {
+    return {Type::PROGRAM_COUNTER, pc};
+  }
+
+  Type type;
+  const void* value;
+};
+
+bool BASE_EXPORT operator < (const StackFrame& lhs, const StackFrame& rhs);
+bool BASE_EXPORT operator == (const StackFrame& lhs, const StackFrame& rhs);
+bool BASE_EXPORT operator != (const StackFrame& lhs, const StackFrame& rhs);
+
+struct BASE_EXPORT Backtrace {
+  Backtrace();
+
+  // If the stack is higher than what can be stored here, the bottom frames
+  // (the ones closer to main()) are stored. Depth of 12 is enough for most
+  // pseudo traces (see above), but not for native traces, where we need more.
+  enum { kMaxFrameCount = 48 };
+  StackFrame frames[kMaxFrameCount];
+  size_t frame_count;
+};
+
+bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
+bool BASE_EXPORT operator!=(const Backtrace& lhs, const Backtrace& rhs);
+
+// The |AllocationContext| is context metadata that is kept for every allocation
+// when heap profiling is enabled. To simplify memory management for book-
+// keeping, this struct has a fixed size.
+struct BASE_EXPORT AllocationContext {
+  AllocationContext();
+  AllocationContext(const Backtrace& backtrace, const char* type_name);
+
+  Backtrace backtrace;
+
+  // Type name of the type stored in the allocated memory. A null pointer
+  // indicates "unknown type". Grouping is done by comparing pointers, not by
+  // deep string comparison. In a component build, where a type name can have a
+  // string literal in several dynamic libraries, this may distort grouping.
+  const char* type_name;
+};
+
+bool BASE_EXPORT operator==(const AllocationContext& lhs,
+                            const AllocationContext& rhs);
+bool BASE_EXPORT operator!=(const AllocationContext& lhs,
+                            const AllocationContext& rhs);
+
+// Struct to store the size and count of the allocations.
+struct AllocationMetrics {
+  size_t size;
+  size_t count;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+template <>
+struct BASE_EXPORT hash<base::trace_event::StackFrame> {
+  size_t operator()(const base::trace_event::StackFrame& frame) const;
+};
+
+template <>
+struct BASE_EXPORT hash<base::trace_event::Backtrace> {
+  size_t operator()(const base::trace_event::Backtrace& backtrace) const;
+};
+
+template <>
+struct BASE_EXPORT hash<base::trace_event::AllocationContext> {
+  size_t operator()(const base::trace_event::AllocationContext& context) const;
+};
+
+}  // BASE_HASH_NAMESPACE
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_context_tracker.cc b/libchrome/base/trace_event/heap_profiler_allocation_context_tracker.cc
new file mode 100644
index 0000000..31f311a
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -0,0 +1,246 @@
+// 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/heap_profiler_allocation_context_tracker.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/atomicops.h"
+#include "base/debug/leak_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <sys/prctl.h>
+#endif
+
+namespace base {
+namespace trace_event {
+
+subtle::Atomic32 AllocationContextTracker::capture_mode_ =
+    static_cast<int32_t>(AllocationContextTracker::CaptureMode::DISABLED);
+
+namespace {
+
+const size_t kMaxStackDepth = 128u;
+const size_t kMaxTaskDepth = 16u;
+AllocationContextTracker* const kInitializingSentinel =
+    reinterpret_cast<AllocationContextTracker*>(-1);
+const char kTracingOverhead[] = "tracing_overhead";
+
+ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
+
+// This function is added to the TLS slot to clean up the instance when the
+// thread exits.
+void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
+  delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
+}
+
+// Cannot call ThreadIdNameManager::GetName because it holds a lock and causes
+// deadlock when lock is already held by ThreadIdNameManager before the current
+// allocation. Gets the thread name from kernel if available or returns a string
+// with id. This function intenionally leaks the allocated strings since they
+// are used to tag allocations even after the thread dies.
+const char* GetAndLeakThreadName() {
+  char name[16];
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  // If the thread name is not set, try to get it from prctl. Thread name might
+  // not be set in cases where the thread started before heap profiling was
+  // enabled.
+  int err = prctl(PR_GET_NAME, name);
+  if (!err) {
+    return strdup(name);
+  }
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+  // Use tid if we don't have a thread name.
+  snprintf(name, sizeof(name), "%lu",
+           static_cast<unsigned long>(PlatformThread::CurrentId()));
+  return strdup(name);
+}
+
+}  // namespace
+
+// static
+AllocationContextTracker*
+AllocationContextTracker::GetInstanceForCurrentThread() {
+  AllocationContextTracker* tracker =
+      static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
+  if (tracker == kInitializingSentinel)
+    return nullptr;  // Re-entrancy case.
+
+  if (!tracker) {
+    g_tls_alloc_ctx_tracker.Set(kInitializingSentinel);
+    tracker = new AllocationContextTracker();
+    g_tls_alloc_ctx_tracker.Set(tracker);
+  }
+
+  return tracker;
+}
+
+AllocationContextTracker::AllocationContextTracker()
+    : thread_name_(nullptr), ignore_scope_depth_(0) {
+  pseudo_stack_.reserve(kMaxStackDepth);
+  task_contexts_.reserve(kMaxTaskDepth);
+}
+AllocationContextTracker::~AllocationContextTracker() {}
+
+// static
+void AllocationContextTracker::SetCurrentThreadName(const char* name) {
+  if (name && capture_mode() != CaptureMode::DISABLED) {
+    GetInstanceForCurrentThread()->thread_name_ = name;
+  }
+}
+
+// static
+void AllocationContextTracker::SetCaptureMode(CaptureMode mode) {
+  // When enabling capturing, also initialize the TLS slot. This does not create
+  // a TLS instance yet.
+  if (mode != CaptureMode::DISABLED && !g_tls_alloc_ctx_tracker.initialized())
+    g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
+
+  // Release ordering ensures that when a thread observes |capture_mode_| to
+  // be true through an acquire load, the TLS slot has been initialized.
+  subtle::Release_Store(&capture_mode_, static_cast<int32_t>(mode));
+}
+
+void AllocationContextTracker::PushPseudoStackFrame(
+    const char* trace_event_name) {
+  // Impose a limit on the height to verify that every push is popped, because
+  // in practice the pseudo stack never grows higher than ~20 frames.
+  if (pseudo_stack_.size() < kMaxStackDepth)
+    pseudo_stack_.push_back(trace_event_name);
+  else
+    NOTREACHED();
+}
+
+void AllocationContextTracker::PopPseudoStackFrame(
+    const char* trace_event_name) {
+  // Guard for stack underflow. If tracing was started with a TRACE_EVENT in
+  // scope, the frame was never pushed, so it is possible that pop is called
+  // on an empty stack.
+  if (pseudo_stack_.empty())
+    return;
+
+  // Assert that pushes and pops are nested correctly. This DCHECK can be
+  // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call
+  // without a corresponding TRACE_EVENT_BEGIN).
+  DCHECK_EQ(trace_event_name, pseudo_stack_.back())
+      << "Encountered an unmatched TRACE_EVENT_END";
+
+  pseudo_stack_.pop_back();
+}
+
+void AllocationContextTracker::PushCurrentTaskContext(const char* context) {
+  DCHECK(context);
+  if (task_contexts_.size() < kMaxTaskDepth)
+    task_contexts_.push_back(context);
+  else
+    NOTREACHED();
+}
+
+void AllocationContextTracker::PopCurrentTaskContext(const char* context) {
+  // Guard for stack underflow. If tracing was started with a TRACE_EVENT in
+  // scope, the context was never pushed, so it is possible that pop is called
+  // on an empty stack.
+  if (task_contexts_.empty())
+    return;
+
+  DCHECK_EQ(context, task_contexts_.back())
+      << "Encountered an unmatched context end";
+  task_contexts_.pop_back();
+}
+
+// static
+AllocationContext AllocationContextTracker::GetContextSnapshot() {
+  AllocationContext ctx;
+
+  if (ignore_scope_depth_) {
+    ctx.backtrace.frames[0] = StackFrame::FromTraceEventName(kTracingOverhead);
+    ctx.type_name = kTracingOverhead;
+    ctx.backtrace.frame_count = 1;
+    return ctx;
+  }
+
+  CaptureMode mode = static_cast<CaptureMode>(
+      subtle::NoBarrier_Load(&capture_mode_));
+
+  auto* backtrace = std::begin(ctx.backtrace.frames);
+  auto* backtrace_end = std::end(ctx.backtrace.frames);
+
+  if (!thread_name_) {
+    // Ignore the string allocation made by GetAndLeakThreadName to avoid
+    // reentrancy.
+    ignore_scope_depth_++;
+    thread_name_ = GetAndLeakThreadName();
+    ANNOTATE_LEAKING_OBJECT_PTR(thread_name_);
+    DCHECK(thread_name_);
+    ignore_scope_depth_--;
+  }
+
+  // Add the thread name as the first entry in pseudo stack.
+  if (thread_name_) {
+    *backtrace++ = StackFrame::FromThreadName(thread_name_);
+  }
+
+  switch (mode) {
+    case CaptureMode::DISABLED:
+      {
+        break;
+      }
+    case CaptureMode::PSEUDO_STACK:
+      {
+        for (const char* event_name: pseudo_stack_) {
+          if (backtrace == backtrace_end) {
+            break;
+          }
+          *backtrace++ = StackFrame::FromTraceEventName(event_name);
+        }
+        break;
+      }
+    case CaptureMode::NATIVE_STACK:
+      {
+        // Backtrace contract requires us to return bottom frames, i.e.
+        // from main() and up. Stack unwinding produces top frames, i.e.
+        // from this point and up until main(). We request many frames to
+        // make sure we reach main(), and then copy bottom portion of them.
+        const void* frames[128];
+        static_assert(arraysize(frames) >= Backtrace::kMaxFrameCount,
+                      "not requesting enough frames to fill Backtrace");
+#if HAVE_TRACE_STACK_FRAME_POINTERS && !defined(OS_NACL)
+        size_t frame_count = debug::TraceStackFramePointers(
+            frames,
+            arraysize(frames),
+            1 /* exclude this function from the trace */ );
+#else
+        size_t frame_count = 0;
+        NOTREACHED();
+#endif
+
+        // Copy frames backwards
+        size_t backtrace_capacity = backtrace_end - backtrace;
+        size_t top_frame_index = (backtrace_capacity >= frame_count) ?
+            0 :
+            frame_count - backtrace_capacity;
+        for (size_t i = frame_count; i > top_frame_index;) {
+          const void* frame = frames[--i];
+          *backtrace++ = StackFrame::FromProgramCounter(frame);
+        }
+        break;
+      }
+  }
+
+  ctx.backtrace.frame_count = backtrace - std::begin(ctx.backtrace.frames);
+
+  // TODO(ssid): Fix crbug.com/594803 to add file name as 3rd dimension
+  // (component name) in the heap profiler and not piggy back on the type name.
+  ctx.type_name = task_contexts_.empty() ? nullptr : task_contexts_.back();
+
+  return ctx;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_context_tracker.h b/libchrome/base/trace_event/heap_profiler_allocation_context_tracker.h
new file mode 100644
index 0000000..454200c
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -0,0 +1,110 @@
+// 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_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+// The allocation context tracker keeps track of thread-local context for heap
+// profiling. It includes a pseudo stack of trace events. On every allocation
+// the tracker provides a snapshot of its context in the form of an
+// |AllocationContext| that is to be stored together with the allocation
+// details.
+class BASE_EXPORT AllocationContextTracker {
+ public:
+  enum class CaptureMode: int32_t {
+    DISABLED,       // Don't capture anything
+    PSEUDO_STACK,   // GetContextSnapshot() returns pseudo stack trace
+    NATIVE_STACK    // GetContextSnapshot() returns native (real) stack trace
+  };
+
+  // Globally sets capturing mode.
+  // TODO(primiano): How to guard against *_STACK -> DISABLED -> *_STACK?
+  static void SetCaptureMode(CaptureMode mode);
+
+  // Returns global capturing mode.
+  inline static CaptureMode capture_mode() {
+    // A little lag after heap profiling is enabled or disabled is fine, it is
+    // more important that the check is as cheap as possible when capturing is
+    // not enabled, so do not issue a memory barrier in the fast path.
+    if (subtle::NoBarrier_Load(&capture_mode_) ==
+            static_cast<int32_t>(CaptureMode::DISABLED))
+      return CaptureMode::DISABLED;
+
+    // In the slow path, an acquire load is required to pair with the release
+    // store in |SetCaptureMode|. This is to ensure that the TLS slot for
+    // the thread-local allocation context tracker has been initialized if
+    // |capture_mode| returns something other than DISABLED.
+    return static_cast<CaptureMode>(subtle::Acquire_Load(&capture_mode_));
+  }
+
+  // Returns the thread-local instance, creating one if necessary. Returns
+  // always a valid instance, unless it is called re-entrantly, in which case
+  // returns nullptr in the nested calls.
+  static AllocationContextTracker* GetInstanceForCurrentThread();
+
+  // Set the thread name in the AllocationContextTracker of the current thread
+  // if capture is enabled.
+  static void SetCurrentThreadName(const char* name);
+
+  // Starts and ends a new ignore scope between which the allocations are
+  // ignored in the heap profiler. A dummy context that short circuits to
+  // "tracing_overhead" is returned for these allocations.
+  void begin_ignore_scope() { ignore_scope_depth_++; }
+  void end_ignore_scope() {
+    if (ignore_scope_depth_)
+      ignore_scope_depth_--;
+  }
+
+  // Pushes a frame onto the thread-local pseudo stack.
+  void PushPseudoStackFrame(const char* trace_event_name);
+
+  // Pops a frame from the thread-local pseudo stack.
+  void PopPseudoStackFrame(const char* trace_event_name);
+
+  // Push and pop current task's context. A stack is used to support nested
+  // tasks and the top of the stack will be used in allocation context.
+  void PushCurrentTaskContext(const char* context);
+  void PopCurrentTaskContext(const char* context);
+
+  // Returns a snapshot of the current thread-local context.
+  AllocationContext GetContextSnapshot();
+
+  ~AllocationContextTracker();
+
+ private:
+  AllocationContextTracker();
+
+  static subtle::Atomic32 capture_mode_;
+
+  // The pseudo stack where frames are |TRACE_EVENT| names.
+  std::vector<const char*> pseudo_stack_;
+
+  // The thread name is used as the first entry in the pseudo stack.
+  const char* thread_name_;
+
+  // Stack of tasks' contexts. Context serves as a different dimension than
+  // pseudo stack to cluster allocations.
+  std::vector<const char*> task_contexts_;
+
+  uint32_t ignore_scope_depth_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc b/libchrome/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
new file mode 100644
index 0000000..3064a6a
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
@@ -0,0 +1,285 @@
+// 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 <stddef.h>
+
+#include <iterator>
+
+#include "base/memory/ref_counted.h"
+#include "base/pending_task.h"
+#include "base/trace_event/heap_profiler.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/trace_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the pseudo stack requires pointer equality,
+// and string interning is unreliable.
+const char kThreadName[] = "TestThread";
+const char kCupcake[] = "Cupcake";
+const char kDonut[] = "Donut";
+const char kEclair[] = "Eclair";
+const char kFroyo[] = "Froyo";
+const char kGingerbread[] = "Gingerbread";
+
+// Asserts that the fixed-size array |expected_backtrace| matches the backtrace
+// in |AllocationContextTracker::GetContextSnapshot|.
+template <size_t N>
+void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
+  AllocationContext ctx =
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->GetContextSnapshot();
+
+  auto* actual = std::begin(ctx.backtrace.frames);
+  auto* actual_bottom = actual + ctx.backtrace.frame_count;
+  auto expected = std::begin(expected_backtrace);
+  auto expected_bottom = std::end(expected_backtrace);
+
+  // Note that this requires the pointers to be equal, this is not doing a deep
+  // string comparison.
+  for (; actual != actual_bottom && expected != expected_bottom;
+       actual++, expected++)
+    ASSERT_EQ(*expected, *actual);
+
+  // Ensure that the height of the stacks is the same.
+  ASSERT_EQ(actual, actual_bottom);
+  ASSERT_EQ(expected, expected_bottom);
+}
+
+void AssertBacktraceContainsOnlyThreadName() {
+  StackFrame t = StackFrame::FromThreadName(kThreadName);
+  AllocationContext ctx =
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->GetContextSnapshot();
+
+  ASSERT_EQ(1u, ctx.backtrace.frame_count);
+  ASSERT_EQ(t, ctx.backtrace.frames[0]);
+}
+
+class AllocationContextTrackerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    TraceConfig config("");
+    TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE);
+    AllocationContextTracker::SetCaptureMode(
+        AllocationContextTracker::CaptureMode::PSEUDO_STACK);
+    AllocationContextTracker::SetCurrentThreadName(kThreadName);
+  }
+
+  void TearDown() override {
+    AllocationContextTracker::SetCaptureMode(
+        AllocationContextTracker::CaptureMode::DISABLED);
+    TraceLog::GetInstance()->SetDisabled();
+  }
+};
+
+// Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
+TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
+  StackFrame t = StackFrame::FromThreadName(kThreadName);
+  StackFrame c = StackFrame::FromTraceEventName(kCupcake);
+  StackFrame d = StackFrame::FromTraceEventName(kDonut);
+  StackFrame e = StackFrame::FromTraceEventName(kEclair);
+  StackFrame f = StackFrame::FromTraceEventName(kFroyo);
+
+  AssertBacktraceContainsOnlyThreadName();
+
+  {
+    TRACE_EVENT0("Testing", kCupcake);
+    StackFrame frame_c[] = {t, c};
+    AssertBacktraceEquals(frame_c);
+
+    {
+      TRACE_EVENT0("Testing", kDonut);
+      StackFrame frame_cd[] = {t, c, d};
+      AssertBacktraceEquals(frame_cd);
+    }
+
+    AssertBacktraceEquals(frame_c);
+
+    {
+      TRACE_EVENT0("Testing", kEclair);
+      StackFrame frame_ce[] = {t, c, e};
+      AssertBacktraceEquals(frame_ce);
+    }
+
+    AssertBacktraceEquals(frame_c);
+  }
+
+  AssertBacktraceContainsOnlyThreadName();
+
+  {
+    TRACE_EVENT0("Testing", kFroyo);
+    StackFrame frame_f[] = {t, f};
+    AssertBacktraceEquals(frame_f);
+  }
+
+  AssertBacktraceContainsOnlyThreadName();
+}
+
+// Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
+// |TRACE_EVENT_END| macros.
+TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
+  StackFrame t = StackFrame::FromThreadName(kThreadName);
+  StackFrame c = StackFrame::FromTraceEventName(kCupcake);
+  StackFrame d = StackFrame::FromTraceEventName(kDonut);
+  StackFrame e = StackFrame::FromTraceEventName(kEclair);
+  StackFrame f = StackFrame::FromTraceEventName(kFroyo);
+
+  StackFrame frame_c[] = {t, c};
+  StackFrame frame_cd[] = {t, c, d};
+  StackFrame frame_ce[] = {t, c, e};
+  StackFrame frame_f[] = {t, f};
+
+  AssertBacktraceContainsOnlyThreadName();
+
+  TRACE_EVENT_BEGIN0("Testing", kCupcake);
+  AssertBacktraceEquals(frame_c);
+
+  TRACE_EVENT_BEGIN0("Testing", kDonut);
+  AssertBacktraceEquals(frame_cd);
+  TRACE_EVENT_END0("Testing", kDonut);
+
+  AssertBacktraceEquals(frame_c);
+
+  TRACE_EVENT_BEGIN0("Testing", kEclair);
+  AssertBacktraceEquals(frame_ce);
+  TRACE_EVENT_END0("Testing", kEclair);
+
+  AssertBacktraceEquals(frame_c);
+  TRACE_EVENT_END0("Testing", kCupcake);
+
+  AssertBacktraceContainsOnlyThreadName();
+
+  TRACE_EVENT_BEGIN0("Testing", kFroyo);
+  AssertBacktraceEquals(frame_f);
+  TRACE_EVENT_END0("Testing", kFroyo);
+
+  AssertBacktraceContainsOnlyThreadName();
+}
+
+TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
+  StackFrame t = StackFrame::FromThreadName(kThreadName);
+  StackFrame c = StackFrame::FromTraceEventName(kCupcake);
+  StackFrame d = StackFrame::FromTraceEventName(kDonut);
+  StackFrame e = StackFrame::FromTraceEventName(kEclair);
+  StackFrame f = StackFrame::FromTraceEventName(kFroyo);
+
+  StackFrame frame_c[] = {t, c};
+  StackFrame frame_cd[] = {t, c, d};
+  StackFrame frame_e[] = {t, e};
+  StackFrame frame_ef[] = {t, e, f};
+
+  AssertBacktraceContainsOnlyThreadName();
+
+  TRACE_EVENT_BEGIN0("Testing", kCupcake);
+  AssertBacktraceEquals(frame_c);
+
+  {
+    TRACE_EVENT0("Testing", kDonut);
+    AssertBacktraceEquals(frame_cd);
+  }
+
+  AssertBacktraceEquals(frame_c);
+  TRACE_EVENT_END0("Testing", kCupcake);
+  AssertBacktraceContainsOnlyThreadName();
+
+  {
+    TRACE_EVENT0("Testing", kEclair);
+    AssertBacktraceEquals(frame_e);
+
+    TRACE_EVENT_BEGIN0("Testing", kFroyo);
+    AssertBacktraceEquals(frame_ef);
+    TRACE_EVENT_END0("Testing", kFroyo);
+    AssertBacktraceEquals(frame_e);
+  }
+
+  AssertBacktraceContainsOnlyThreadName();
+}
+
+TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
+  StackFrame t = StackFrame::FromThreadName(kThreadName);
+  StackFrame c = StackFrame::FromTraceEventName(kCupcake);
+  StackFrame f = StackFrame::FromTraceEventName(kFroyo);
+
+  // Push 11 events onto the pseudo stack.
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kCupcake);
+
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kDonut);
+  TRACE_EVENT0("Testing", kEclair);
+  TRACE_EVENT0("Testing", kFroyo);
+
+  {
+    TRACE_EVENT0("Testing", kGingerbread);
+    AllocationContext ctx =
+        AllocationContextTracker::GetInstanceForCurrentThread()
+            ->GetContextSnapshot();
+
+    // The pseudo stack relies on pointer equality, not deep string comparisons.
+    ASSERT_EQ(t, ctx.backtrace.frames[0]);
+    ASSERT_EQ(c, ctx.backtrace.frames[1]);
+    ASSERT_EQ(f, ctx.backtrace.frames[11]);
+  }
+
+  {
+    AllocationContext ctx =
+        AllocationContextTracker::GetInstanceForCurrentThread()
+            ->GetContextSnapshot();
+    ASSERT_EQ(t, ctx.backtrace.frames[0]);
+    ASSERT_EQ(c, ctx.backtrace.frames[1]);
+    ASSERT_EQ(f, ctx.backtrace.frames[11]);
+  }
+}
+
+TEST_F(AllocationContextTrackerTest, TrackTaskContext) {
+  const char kContext1[] = "context1";
+  const char kContext2[] = "context2";
+  {
+    // The context from the scoped task event should be used as type name.
+    TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event1(kContext1);
+    AllocationContext ctx1 =
+        AllocationContextTracker::GetInstanceForCurrentThread()
+            ->GetContextSnapshot();
+    ASSERT_EQ(kContext1, ctx1.type_name);
+
+    // In case of nested events, the last event's context should be used.
+    TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event2(kContext2);
+    AllocationContext ctx2 =
+        AllocationContextTracker::GetInstanceForCurrentThread()
+            ->GetContextSnapshot();
+    ASSERT_EQ(kContext2, ctx2.type_name);
+  }
+
+  // Type should be nullptr without task event.
+  AllocationContext ctx =
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->GetContextSnapshot();
+  ASSERT_FALSE(ctx.type_name);
+}
+
+TEST_F(AllocationContextTrackerTest, IgnoreAllocationTest) {
+  TRACE_EVENT0("Testing", kCupcake);
+  TRACE_EVENT0("Testing", kDonut);
+  HEAP_PROFILER_SCOPED_IGNORE;
+  AllocationContext ctx =
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->GetContextSnapshot();
+  const StringPiece kTracingOverhead("tracing_overhead");
+  ASSERT_EQ(kTracingOverhead,
+            static_cast<const char*>(ctx.backtrace.frames[0].value));
+  ASSERT_EQ(1u, ctx.backtrace.frame_count);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_register.cc b/libchrome/base/trace_event/heap_profiler_allocation_register.cc
new file mode 100644
index 0000000..2c2cd37
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_register.cc
@@ -0,0 +1,180 @@
+// 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/heap_profiler_allocation_register.h"
+
+#include <algorithm>
+
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+AllocationRegister::ConstIterator::ConstIterator(
+    const AllocationRegister& alloc_register, AllocationIndex index)
+    : register_(alloc_register),
+      index_(index) {}
+
+void AllocationRegister::ConstIterator::operator++() {
+  index_ = register_.allocations_.Next(index_ + 1);
+}
+
+bool AllocationRegister::ConstIterator::operator!=(
+    const ConstIterator& other) const {
+  return index_ != other.index_;
+}
+
+AllocationRegister::Allocation
+AllocationRegister::ConstIterator::operator*() const {
+  return register_.GetAllocation(index_);
+}
+
+size_t AllocationRegister::BacktraceHasher::operator () (
+    const Backtrace& backtrace) const {
+  const size_t kSampleLength = 10;
+
+  uintptr_t total_value = 0;
+
+  size_t head_end = std::min(backtrace.frame_count, kSampleLength);
+  for (size_t i = 0; i != head_end; ++i) {
+    total_value += reinterpret_cast<uintptr_t>(backtrace.frames[i].value);
+  }
+
+  size_t tail_start = backtrace.frame_count -
+      std::min(backtrace.frame_count - head_end, kSampleLength);
+  for (size_t i = tail_start; i != backtrace.frame_count; ++i) {
+    total_value += reinterpret_cast<uintptr_t>(backtrace.frames[i].value);
+  }
+
+  total_value += backtrace.frame_count;
+
+  // These magic constants give best results in terms of average collisions
+  // per backtrace. They were found by replaying real backtraces from Linux
+  // and Android against different hash functions.
+  return (total_value * 131101) >> 14;
+}
+
+size_t AllocationRegister::AddressHasher::operator () (
+    const void* address) const {
+  // The multiplicative hashing scheme from [Knuth 1998]. The value of |a| has
+  // been chosen carefully based on measurements with real-word data (addresses
+  // recorded from a Chrome trace run). It is the first prime after 2^17. For
+  // |shift|, 13, 14 and 15 yield good results. These values are tuned to 2^18
+  // buckets. Microbenchmarks show that this simple scheme outperforms fancy
+  // hashes like Murmur3 by 20 to 40 percent.
+  const uintptr_t key = reinterpret_cast<uintptr_t>(address);
+  const uintptr_t a = 131101;
+  const uintptr_t shift = 14;
+  const uintptr_t h = (key * a) >> shift;
+  return h;
+}
+
+AllocationRegister::AllocationRegister()
+    : AllocationRegister(kAllocationCapacity, kBacktraceCapacity) {}
+
+AllocationRegister::AllocationRegister(size_t allocation_capacity,
+                                       size_t backtrace_capacity)
+    : allocations_(allocation_capacity),
+      backtraces_(backtrace_capacity) {}
+
+AllocationRegister::~AllocationRegister() {
+}
+
+void AllocationRegister::Insert(const void* address,
+                                size_t size,
+                                const AllocationContext& context) {
+  DCHECK(address != nullptr);
+  if (size == 0) {
+    return;
+  }
+
+  AllocationInfo info = {
+      size,
+      context.type_name,
+      InsertBacktrace(context.backtrace)
+  };
+
+  // Try to insert the allocation.
+  auto index_and_flag = allocations_.Insert(address, info);
+  if (!index_and_flag.second) {
+    // |address| is already there - overwrite the allocation info.
+    auto& old_info = allocations_.Get(index_and_flag.first).second;
+    RemoveBacktrace(old_info.backtrace_index);
+    old_info = info;
+  }
+}
+
+void AllocationRegister::Remove(const void* address) {
+  auto index = allocations_.Find(address);
+  if (index == AllocationMap::kInvalidKVIndex) {
+    return;
+  }
+
+  const AllocationInfo& info = allocations_.Get(index).second;
+  RemoveBacktrace(info.backtrace_index);
+  allocations_.Remove(index);
+}
+
+bool AllocationRegister::Get(const void* address,
+                             Allocation* out_allocation) const {
+  auto index = allocations_.Find(address);
+  if (index == AllocationMap::kInvalidKVIndex) {
+    return false;
+  }
+
+  if (out_allocation) {
+    *out_allocation = GetAllocation(index);
+  }
+  return true;
+}
+
+AllocationRegister::ConstIterator AllocationRegister::begin() const {
+  return ConstIterator(*this, allocations_.Next(0));
+}
+
+AllocationRegister::ConstIterator AllocationRegister::end() const {
+  return ConstIterator(*this, AllocationMap::kInvalidKVIndex);
+}
+
+void AllocationRegister::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) const {
+  size_t allocated = sizeof(AllocationRegister);
+  size_t resident = sizeof(AllocationRegister)
+                    + allocations_.EstimateUsedMemory()
+                    + backtraces_.EstimateUsedMemory();
+  overhead->Add("AllocationRegister", allocated, resident);
+}
+
+AllocationRegister::BacktraceMap::KVIndex AllocationRegister::InsertBacktrace(
+    const Backtrace& backtrace) {
+  auto index = backtraces_.Insert(backtrace, 0).first;
+  auto& backtrace_and_count = backtraces_.Get(index);
+  backtrace_and_count.second++;
+  return index;
+}
+
+void AllocationRegister::RemoveBacktrace(BacktraceMap::KVIndex index) {
+  auto& backtrace_and_count = backtraces_.Get(index);
+  if (--backtrace_and_count.second == 0) {
+    // Backtrace is not referenced anymore - remove it.
+    backtraces_.Remove(index);
+  }
+}
+
+AllocationRegister::Allocation AllocationRegister::GetAllocation(
+    AllocationMap::KVIndex index) const {
+  const auto& address_and_info = allocations_.Get(index);
+  const auto& backtrace_and_count = backtraces_.Get(
+      address_and_info.second.backtrace_index);
+  return {
+      address_and_info.first,
+      address_and_info.second.size,
+      AllocationContext(
+          backtrace_and_count.first,
+          address_and_info.second.type_name)
+  };
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_register.h b/libchrome/base/trace_event/heap_profiler_allocation_register.h
new file mode 100644
index 0000000..86e2721
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_register.h
@@ -0,0 +1,356 @@
+// 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_HEAP_PROFILER_ALLOCATION_REGISTER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+
+#include "base/bits.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/process/process_metrics.h"
+#include "base/template_util.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+class AllocationRegisterTest;
+
+namespace internal {
+
+// Allocates a region of virtual address space of |size| rounded up to the
+// system page size. The memory is zeroed by the system. A guard page is
+// added after the end.
+void* AllocateGuardedVirtualMemory(size_t size);
+
+// Frees a region of virtual address space allocated by a call to
+// |AllocateVirtualMemory|.
+void FreeGuardedVirtualMemory(void* address, size_t allocated_size);
+
+// Hash map that mmaps memory only once in the constructor. Its API is
+// similar to std::unordered_map, only index (KVIndex) is used to address
+template <size_t NumBuckets, class Key, class Value, class KeyHasher>
+class FixedHashMap {
+  // To keep things simple we don't call destructors.
+  static_assert(is_trivially_destructible<Key>::value &&
+                    is_trivially_destructible<Value>::value,
+                "Key and Value shouldn't have destructors");
+ public:
+  using KVPair = std::pair<const Key, Value>;
+
+  // For implementation simplicity API uses integer index instead
+  // of iterators. Most operations (except FindValidIndex) on KVIndex
+  // are O(1).
+  using KVIndex = size_t;
+  static const KVIndex kInvalidKVIndex = static_cast<KVIndex>(-1);
+
+  // Capacity controls how many items this hash map can hold, and largely
+  // affects memory footprint.
+  FixedHashMap(size_t capacity)
+    : num_cells_(capacity),
+      cells_(static_cast<Cell*>(
+          AllocateGuardedVirtualMemory(num_cells_ * sizeof(Cell)))),
+      buckets_(static_cast<Bucket*>(
+          AllocateGuardedVirtualMemory(NumBuckets * sizeof(Bucket)))),
+      free_list_(nullptr),
+      next_unused_cell_(0) {}
+
+  ~FixedHashMap() {
+    FreeGuardedVirtualMemory(cells_, num_cells_ * sizeof(Cell));
+    FreeGuardedVirtualMemory(buckets_, NumBuckets * sizeof(Bucket));
+  }
+
+  std::pair<KVIndex, bool> Insert(const Key& key, const Value& value) {
+    Cell** p_cell = Lookup(key);
+    Cell* cell = *p_cell;
+    if (cell) {
+      return {static_cast<KVIndex>(cell - cells_), false};  // not inserted
+    }
+
+    // Get a free cell and link it.
+    *p_cell = cell = GetFreeCell();
+    cell->p_prev = p_cell;
+    cell->next = nullptr;
+
+    // Initialize key/value pair. Since key is 'const Key' this is the
+    // only way to initialize it.
+    new (&cell->kv) KVPair(key, value);
+
+    return {static_cast<KVIndex>(cell - cells_), true};  // inserted
+  }
+
+  void Remove(KVIndex index) {
+    DCHECK_LT(index, next_unused_cell_);
+
+    Cell* cell = &cells_[index];
+
+    // Unlink the cell.
+    *cell->p_prev = cell->next;
+    if (cell->next) {
+      cell->next->p_prev = cell->p_prev;
+    }
+    cell->p_prev = nullptr;  // mark as free
+
+    // Add it to the free list.
+    cell->next = free_list_;
+    free_list_ = cell;
+  }
+
+  KVIndex Find(const Key& key) const {
+    Cell* cell = *Lookup(key);
+    return cell ? static_cast<KVIndex>(cell - cells_) : kInvalidKVIndex;
+  }
+
+  KVPair& Get(KVIndex index) {
+    return cells_[index].kv;
+  }
+
+  const KVPair& Get(KVIndex index) const {
+    return cells_[index].kv;
+  }
+
+  // Finds next index that has a KVPair associated with it. Search starts
+  // with the specified index. Returns kInvalidKVIndex if nothing was found.
+  // To find the first valid index, call this function with 0. Continue
+  // calling with the last_index + 1 until kInvalidKVIndex is returned.
+  KVIndex Next(KVIndex index) const {
+    for (;index < next_unused_cell_; ++index) {
+      if (cells_[index].p_prev) {
+        return index;
+      }
+    }
+    return kInvalidKVIndex;
+  }
+
+  // Estimates number of bytes used in allocated memory regions.
+  size_t EstimateUsedMemory() const {
+    size_t page_size = base::GetPageSize();
+    // |next_unused_cell_| is the first cell that wasn't touched, i.e.
+    // it's the number of touched cells.
+    return bits::Align(sizeof(Cell) * next_unused_cell_, page_size) +
+           bits::Align(sizeof(Bucket) * NumBuckets, page_size);
+  }
+
+ private:
+  friend base::trace_event::AllocationRegisterTest;
+
+  struct Cell {
+    KVPair kv;
+    Cell* next;
+
+    // Conceptually this is |prev| in a doubly linked list. However, buckets
+    // also participate in the bucket's cell list - they point to the list's
+    // head and also need to be linked / unlinked properly. To treat these two
+    // cases uniformly, instead of |prev| we're storing "pointer to a Cell*
+    // that points to this Cell" kind of thing. So |p_prev| points to a bucket
+    // for the first cell in a list, and points to |next| of the previous cell
+    // for any other cell. With that Lookup() is the only function that handles
+    // buckets / cells differently.
+    // If |p_prev| is nullptr, the cell is in the free list.
+    Cell** p_prev;
+  };
+
+  using Bucket = Cell*;
+
+  // Returns a pointer to the cell that contains or should contain the entry
+  // for |key|. The pointer may point at an element of |buckets_| or at the
+  // |next| member of an element of |cells_|.
+  Cell** Lookup(const Key& key) const {
+    // The list head is in |buckets_| at the hash offset.
+    Cell** p_cell = &buckets_[Hash(key)];
+
+    // Chase down the list until the cell that holds |key| is found,
+    // or until the list ends.
+    while (*p_cell && (*p_cell)->kv.first != key) {
+      p_cell = &(*p_cell)->next;
+    }
+
+    return p_cell;
+  }
+
+  // Returns a cell that is not being used to store an entry (either by
+  // recycling from the free list or by taking a fresh cell).
+  Cell* GetFreeCell() {
+    // First try to re-use a cell from the free list.
+    if (free_list_) {
+      Cell* cell = free_list_;
+      free_list_ = cell->next;
+      return cell;
+    }
+
+    // Otherwise pick the next cell that has not been touched before.
+    size_t idx = next_unused_cell_;
+    next_unused_cell_++;
+
+    // If the hash table has too little capacity (when too little address space
+    // was reserved for |cells_|), |next_unused_cell_| can be an index outside
+    // of the allocated storage. A guard page is allocated there to crash the
+    // program in that case. There are alternative solutions:
+    // - Deal with it, increase capacity by reallocating |cells_|.
+    // - Refuse to insert and let the caller deal with it.
+    // Because free cells are re-used before accessing fresh cells with a higher
+    // index, and because reserving address space without touching it is cheap,
+    // the simplest solution is to just allocate a humongous chunk of address
+    // space.
+
+    DCHECK_LT(next_unused_cell_, num_cells_ + 1);
+
+    return &cells_[idx];
+  }
+
+  // Returns a value in the range [0, NumBuckets - 1] (inclusive).
+  size_t Hash(const Key& key) const {
+    if (NumBuckets == (NumBuckets & ~(NumBuckets - 1))) {
+      // NumBuckets is a power of 2.
+      return KeyHasher()(key) & (NumBuckets - 1);
+    } else {
+      return KeyHasher()(key) % NumBuckets;
+    }
+  }
+
+  // Number of cells.
+  size_t const num_cells_;
+
+  // The array of cells. This array is backed by mmapped memory. Lower indices
+  // are accessed first, higher indices are accessed only when the |free_list_|
+  // is empty. This is to minimize the amount of resident memory used.
+  Cell* const cells_;
+
+  // The array of buckets (pointers into |cells_|). |buckets_[Hash(key)]| will
+  // contain the pointer to the linked list of cells for |Hash(key)|.
+  // This array is backed by mmapped memory.
+  mutable Bucket* buckets_;
+
+  // The head of the free list.
+  Cell* free_list_;
+
+  // The index of the first element of |cells_| that has not been used before.
+  // If the free list is empty and a new cell is needed, the cell at this index
+  // is used. This is the high water mark for the number of entries stored.
+  size_t next_unused_cell_;
+
+  DISALLOW_COPY_AND_ASSIGN(FixedHashMap);
+};
+
+}  // namespace internal
+
+class TraceEventMemoryOverhead;
+
+// The allocation register keeps track of all allocations that have not been
+// freed. Internally it has two hashtables: one for Backtraces and one for
+// actual allocations. Sizes of both hashtables are fixed, and this class
+// allocates (mmaps) only in its constructor.
+class BASE_EXPORT AllocationRegister {
+ public:
+  // Details about an allocation.
+  struct Allocation {
+    const void* address;
+    size_t size;
+    AllocationContext context;
+  };
+
+  // An iterator that iterates entries in no particular order.
+  class BASE_EXPORT ConstIterator {
+   public:
+    void operator++();
+    bool operator!=(const ConstIterator& other) const;
+    Allocation operator*() const;
+
+   private:
+    friend class AllocationRegister;
+    using AllocationIndex = size_t;
+
+    ConstIterator(const AllocationRegister& alloc_register,
+                  AllocationIndex index);
+
+    const AllocationRegister& register_;
+    AllocationIndex index_;
+  };
+
+  AllocationRegister();
+  AllocationRegister(size_t allocation_capacity, size_t backtrace_capacity);
+
+  ~AllocationRegister();
+
+  // Inserts allocation details into the table. If the address was present
+  // already, its details are updated. |address| must not be null.
+  void Insert(const void* address,
+              size_t size,
+              const AllocationContext& context);
+
+  // Removes the address from the table if it is present. It is ok to call this
+  // with a null pointer.
+  void Remove(const void* address);
+
+  // Finds allocation for the address and fills |out_allocation|.
+  bool Get(const void* address, Allocation* out_allocation) const;
+
+  ConstIterator begin() const;
+  ConstIterator end() const;
+
+  // Estimates memory overhead including |sizeof(AllocationRegister)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) const;
+
+ private:
+  friend AllocationRegisterTest;
+
+  // Expect max 1.5M allocations. Number of buckets is 2^18 for optimal
+  // hashing and should be changed together with AddressHasher.
+  static const size_t kAllocationBuckets = 1 << 18;
+  static const size_t kAllocationCapacity = 1500000;
+
+  // Expect max 2^15 unique backtraces. Can be changed to 2^16 without
+  // needing to tweak BacktraceHasher implementation.
+  static const size_t kBacktraceBuckets = 1 << 15;
+  static const size_t kBacktraceCapacity = kBacktraceBuckets;
+
+  struct BacktraceHasher {
+    size_t operator () (const Backtrace& backtrace) const;
+  };
+
+  using BacktraceMap = internal::FixedHashMap<
+      kBacktraceBuckets,
+      Backtrace,
+      size_t, // Number of references to the backtrace (the key). Incremented
+              // when an allocation that references the backtrace is inserted,
+              // and decremented when the allocation is removed. When the
+              // number drops to zero, the backtrace is removed from the map.
+      BacktraceHasher>;
+
+  struct AllocationInfo {
+    size_t size;
+    const char* type_name;
+    BacktraceMap::KVIndex backtrace_index;
+  };
+
+  struct AddressHasher {
+    size_t operator () (const void* address) const;
+  };
+
+  using AllocationMap = internal::FixedHashMap<
+      kAllocationBuckets,
+      const void*,
+      AllocationInfo,
+      AddressHasher>;
+
+  BacktraceMap::KVIndex InsertBacktrace(const Backtrace& backtrace);
+  void RemoveBacktrace(BacktraceMap::KVIndex index);
+
+  Allocation GetAllocation(AllocationMap::KVIndex) const;
+
+  AllocationMap allocations_;
+  BacktraceMap backtraces_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllocationRegister);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
diff --git a/libchrome/base/trace_event/heap_profiler_allocation_register_posix.cc b/libchrome/base/trace_event/heap_profiler_allocation_register_posix.cc
new file mode 100644
index 0000000..94eeb4d
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_allocation_register_posix.cc
@@ -0,0 +1,58 @@
+// 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/heap_profiler_allocation_register.h"
+
+#include <stddef.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "base/bits.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+namespace base {
+namespace trace_event {
+namespace internal {
+
+namespace {
+size_t GetGuardSize() {
+  return GetPageSize();
+}
+}
+
+void* AllocateGuardedVirtualMemory(size_t size) {
+  size = bits::Align(size, GetPageSize());
+
+  // Add space for a guard page at the end.
+  size_t map_size = size + GetGuardSize();
+
+  void* addr = mmap(nullptr, map_size, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  PCHECK(addr != MAP_FAILED);
+
+  // Mark the last page of the allocated address space as inaccessible
+  // (PROT_NONE). The read/write accessible space is still at least |min_size|
+  // bytes.
+  void* guard_addr =
+      reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) + size);
+  int result = mprotect(guard_addr, GetGuardSize(), PROT_NONE);
+  PCHECK(result == 0);
+
+  return addr;
+}
+
+void FreeGuardedVirtualMemory(void* address, size_t allocated_size) {
+  size_t size = bits::Align(allocated_size, GetPageSize()) + GetGuardSize();
+  munmap(address, size);
+}
+
+}  // namespace internal
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_heap_dump_writer.cc b/libchrome/base/trace_event/heap_profiler_heap_dump_writer.cc
new file mode 100644
index 0000000..1bf06db
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_heap_dump_writer.cc
@@ -0,0 +1,323 @@
+// 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/heap_profiler_heap_dump_writer.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <iterator>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_log.h"
+
+// Most of what the |HeapDumpWriter| does is aggregating detailed information
+// about the heap and deciding what to dump. The Input to this process is a list
+// of |AllocationContext|s and size pairs.
+//
+// The pairs are grouped into |Bucket|s. A bucket is a group of (context, size)
+// pairs where the properties of the contexts share a prefix. (Type name is
+// considered a list of length one here.) First all pairs are put into one
+// bucket that represents the entire heap. Then this bucket is recursively
+// broken down into smaller buckets. Each bucket keeps track of whether further
+// breakdown is possible.
+
+namespace base {
+namespace trace_event {
+namespace internal {
+namespace {
+
+// Denotes a property of |AllocationContext| to break down by.
+enum class BreakDownMode { kByBacktrace, kByTypeName };
+
+// A group of bytes for which the context shares a prefix.
+struct Bucket {
+  Bucket()
+      : size(0),
+        count(0),
+        backtrace_cursor(0),
+        is_broken_down_by_type_name(false) {}
+
+  std::vector<std::pair<const AllocationContext*, AllocationMetrics>>
+      metrics_by_context;
+
+  // The sum of the sizes of |metrics_by_context|.
+  size_t size;
+
+  // The sum of number of allocations of |metrics_by_context|.
+  size_t count;
+
+  // The index of the stack frame that has not yet been broken down by. For all
+  // elements in this bucket, the stack frames 0 up to (but not including) the
+  // cursor, must be equal.
+  size_t backtrace_cursor;
+
+  // When true, the type name for all elements in this bucket must be equal.
+  bool is_broken_down_by_type_name;
+};
+
+// Comparison operator to order buckets by their size.
+bool operator<(const Bucket& lhs, const Bucket& rhs) {
+  return lhs.size < rhs.size;
+}
+
+// Groups the allocations in the bucket by |break_by|. The buckets in the
+// returned list will have |backtrace_cursor| advanced or
+// |is_broken_down_by_type_name| set depending on the property to group by.
+std::vector<Bucket> GetSubbuckets(const Bucket& bucket,
+                                  BreakDownMode break_by) {
+  base::hash_map<const void*, Bucket> breakdown;
+
+
+  if (break_by == BreakDownMode::kByBacktrace) {
+    for (const auto& context_and_metrics : bucket.metrics_by_context) {
+      const Backtrace& backtrace = context_and_metrics.first->backtrace;
+      const StackFrame* begin = std::begin(backtrace.frames);
+      const StackFrame* end = begin + backtrace.frame_count;
+      const StackFrame* cursor = begin + bucket.backtrace_cursor;
+
+      DCHECK_LE(cursor, end);
+
+      if (cursor != end) {
+        Bucket& subbucket = breakdown[cursor->value];
+        subbucket.size += context_and_metrics.second.size;
+        subbucket.count += context_and_metrics.second.count;
+        subbucket.metrics_by_context.push_back(context_and_metrics);
+        subbucket.backtrace_cursor = bucket.backtrace_cursor + 1;
+        subbucket.is_broken_down_by_type_name =
+            bucket.is_broken_down_by_type_name;
+        DCHECK_GT(subbucket.size, 0u);
+        DCHECK_GT(subbucket.count, 0u);
+      }
+    }
+  } else if (break_by == BreakDownMode::kByTypeName) {
+    if (!bucket.is_broken_down_by_type_name) {
+      for (const auto& context_and_metrics : bucket.metrics_by_context) {
+        const AllocationContext* context = context_and_metrics.first;
+        Bucket& subbucket = breakdown[context->type_name];
+        subbucket.size += context_and_metrics.second.size;
+        subbucket.count += context_and_metrics.second.count;
+        subbucket.metrics_by_context.push_back(context_and_metrics);
+        subbucket.backtrace_cursor = bucket.backtrace_cursor;
+        subbucket.is_broken_down_by_type_name = true;
+        DCHECK_GT(subbucket.size, 0u);
+        DCHECK_GT(subbucket.count, 0u);
+      }
+    }
+  }
+
+  std::vector<Bucket> buckets;
+  buckets.reserve(breakdown.size());
+  for (auto key_bucket : breakdown)
+    buckets.push_back(key_bucket.second);
+
+  return buckets;
+}
+
+// Breaks down the bucket by |break_by|. Returns only buckets that contribute
+// more than |min_size_bytes| to the total size. The long tail is omitted.
+std::vector<Bucket> BreakDownBy(const Bucket& bucket,
+                                BreakDownMode break_by,
+                                size_t min_size_bytes) {
+  std::vector<Bucket> buckets = GetSubbuckets(bucket, break_by);
+
+  // Ensure that |buckets| is a max-heap (the data structure, not memory heap),
+  // so its front contains the largest bucket. Buckets should be iterated
+  // ordered by size, but sorting the vector is overkill because the long tail
+  // of small buckets will be discarded. By using a max-heap, the optimal case
+  // where all but the first bucket are discarded is O(n). The worst case where
+  // no bucket is discarded is doing a heap sort, which is O(n log n).
+  std::make_heap(buckets.begin(), buckets.end());
+
+  // Keep including buckets until adding one would increase the number of
+  // bytes accounted for by |min_size_bytes|. The large buckets end up in
+  // [it, end()), [begin(), it) is the part that contains the max-heap
+  // of small buckets.
+  std::vector<Bucket>::iterator it;
+  for (it = buckets.end(); it != buckets.begin(); --it) {
+    if (buckets.front().size < min_size_bytes)
+      break;
+
+    // Put the largest bucket in [begin, it) at |it - 1| and max-heapify
+    // [begin, it - 1). This puts the next largest bucket at |buckets.front()|.
+    std::pop_heap(buckets.begin(), it);
+  }
+
+  // At this point, |buckets| looks like this (numbers are bucket sizes):
+  //
+  // <-- max-heap of small buckets --->
+  //                                  <-- large buckets by ascending size -->
+  // [ 19 | 11 | 13 | 7 | 2 | 5 | ... | 83 | 89 | 97 ]
+  //   ^                                ^              ^
+  //   |                                |              |
+  //   begin()                          it             end()
+
+  // Discard the long tail of buckets that contribute less than a percent.
+  buckets.erase(buckets.begin(), it);
+
+  return buckets;
+}
+
+}  // namespace
+
+bool operator<(Entry lhs, Entry rhs) {
+  // There is no need to compare |size|. If the backtrace and type name are
+  // equal then the sizes must be equal as well.
+  return std::tie(lhs.stack_frame_id, lhs.type_id) <
+         std::tie(rhs.stack_frame_id, rhs.type_id);
+}
+
+HeapDumpWriter::HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
+                               TypeNameDeduplicator* type_name_deduplicator,
+                               uint32_t breakdown_threshold_bytes)
+    : stack_frame_deduplicator_(stack_frame_deduplicator),
+      type_name_deduplicator_(type_name_deduplicator),
+      breakdown_threshold_bytes_(breakdown_threshold_bytes) {
+}
+
+HeapDumpWriter::~HeapDumpWriter() {}
+
+bool HeapDumpWriter::AddEntryForBucket(const Bucket& bucket) {
+  // The contexts in the bucket are all different, but the [begin, cursor) range
+  // is equal for all contexts in the bucket, and the type names are the same if
+  // |is_broken_down_by_type_name| is set.
+  DCHECK(!bucket.metrics_by_context.empty());
+
+  const AllocationContext* context = bucket.metrics_by_context.front().first;
+
+  const StackFrame* backtrace_begin = std::begin(context->backtrace.frames);
+  const StackFrame* backtrace_end = backtrace_begin + bucket.backtrace_cursor;
+  DCHECK_LE(bucket.backtrace_cursor, arraysize(context->backtrace.frames));
+
+  Entry entry;
+  entry.stack_frame_id = stack_frame_deduplicator_->Insert(
+      backtrace_begin, backtrace_end);
+
+  // Deduplicate the type name, or use ID -1 if type name is not set.
+  entry.type_id = bucket.is_broken_down_by_type_name
+                      ? type_name_deduplicator_->Insert(context->type_name)
+                      : -1;
+
+  entry.size = bucket.size;
+  entry.count = bucket.count;
+
+  auto position_and_inserted = entries_.insert(entry);
+  return position_and_inserted.second;
+}
+
+void HeapDumpWriter::BreakDown(const Bucket& bucket) {
+  auto by_backtrace = BreakDownBy(bucket,
+                                  BreakDownMode::kByBacktrace,
+                                  breakdown_threshold_bytes_);
+  auto by_type_name = BreakDownBy(bucket,
+                                  BreakDownMode::kByTypeName,
+                                  breakdown_threshold_bytes_);
+
+  // Insert entries for the buckets. If a bucket was not present before, it has
+  // not been broken down before, so recursively continue breaking down in that
+  // case. There might be multiple routes to the same entry (first break down
+  // by type name, then by backtrace, or first by backtrace and then by type),
+  // so a set is used to avoid dumping and breaking down entries more than once.
+
+  for (const Bucket& subbucket : by_backtrace)
+    if (AddEntryForBucket(subbucket))
+      BreakDown(subbucket);
+
+  for (const Bucket& subbucket : by_type_name)
+    if (AddEntryForBucket(subbucket))
+      BreakDown(subbucket);
+}
+
+const std::set<Entry>& HeapDumpWriter::Summarize(
+    const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context) {
+  // Start with one bucket that represents the entire heap. Iterate by
+  // reference, because the allocation contexts are going to point to allocation
+  // contexts stored in |metrics_by_context|.
+  Bucket root_bucket;
+  for (const auto& context_and_metrics : metrics_by_context) {
+    DCHECK_GT(context_and_metrics.second.size, 0u);
+    DCHECK_GT(context_and_metrics.second.count, 0u);
+    const AllocationContext* context = &context_and_metrics.first;
+    root_bucket.metrics_by_context.push_back(
+        std::make_pair(context, context_and_metrics.second));
+    root_bucket.size += context_and_metrics.second.size;
+    root_bucket.count += context_and_metrics.second.count;
+  }
+
+  AddEntryForBucket(root_bucket);
+
+  // Recursively break down the heap and fill |entries_| with entries to dump.
+  BreakDown(root_bucket);
+
+  return entries_;
+}
+
+std::unique_ptr<TracedValue> Serialize(const std::set<Entry>& entries) {
+  std::string buffer;
+  std::unique_ptr<TracedValue> traced_value(new TracedValue);
+
+  traced_value->BeginArray("entries");
+
+  for (const Entry& entry : entries) {
+    traced_value->BeginDictionary();
+
+    // Format size as hexadecimal string into |buffer|.
+    SStringPrintf(&buffer, "%" PRIx64, static_cast<uint64_t>(entry.size));
+    traced_value->SetString("size", buffer);
+
+    SStringPrintf(&buffer, "%" PRIx64, static_cast<uint64_t>(entry.count));
+    traced_value->SetString("count", buffer);
+
+    if (entry.stack_frame_id == -1) {
+      // An empty backtrace (which will have ID -1) is represented by the empty
+      // string, because there is no leaf frame to reference in |stackFrames|.
+      traced_value->SetString("bt", "");
+    } else {
+      // Format index of the leaf frame as a string, because |stackFrames| is a
+      // dictionary, not an array.
+      SStringPrintf(&buffer, "%i", entry.stack_frame_id);
+      traced_value->SetString("bt", buffer);
+    }
+
+    // Type ID -1 (cumulative size for all types) is represented by the absence
+    // of the "type" key in the dictionary.
+    if (entry.type_id != -1) {
+      // Format the type ID as a string.
+      SStringPrintf(&buffer, "%i", entry.type_id);
+      traced_value->SetString("type", buffer);
+    }
+
+    traced_value->EndDictionary();
+  }
+
+  traced_value->EndArray();  // "entries"
+  return traced_value;
+}
+
+}  // namespace internal
+
+std::unique_ptr<TracedValue> ExportHeapDump(
+    const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context,
+    const MemoryDumpSessionState& session_state) {
+  internal::HeapDumpWriter writer(
+      session_state.stack_frame_deduplicator(),
+      session_state.type_name_deduplicator(),
+      session_state.memory_dump_config().heap_profiler_options
+          .breakdown_threshold_bytes);
+  return Serialize(writer.Summarize(metrics_by_context));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_heap_dump_writer.h b/libchrome/base/trace_event/heap_profiler_heap_dump_writer.h
new file mode 100644
index 0000000..6e9d29d
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_heap_dump_writer.h
@@ -0,0 +1,113 @@
+// 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_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <set>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpSessionState;
+class StackFrameDeduplicator;
+class TracedValue;
+class TypeNameDeduplicator;
+
+// Aggregates |metrics_by_context|, recursively breaks down the heap, and
+// returns a traced value with an "entries" array that can be dumped in the
+// trace log, following the format described in https://goo.gl/KY7zVE. The
+// number of entries is kept reasonable because long tails are not included.
+BASE_EXPORT std::unique_ptr<TracedValue> ExportHeapDump(
+    const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context,
+    const MemoryDumpSessionState& session_state);
+
+namespace internal {
+
+namespace {
+struct Bucket;
+}
+
+// An entry in the "entries" array as described in https://goo.gl/KY7zVE.
+struct BASE_EXPORT Entry {
+  size_t size;
+  size_t count;
+
+  // References a backtrace in the stack frame deduplicator. -1 means empty
+  // backtrace (the root of the tree).
+  int stack_frame_id;
+
+  // References a type name in the type name deduplicator. -1 indicates that
+  // the size is the cumulative size for all types (the root of the tree).
+  int type_id;
+};
+
+// Comparison operator to enable putting |Entry| in a |std::set|.
+BASE_EXPORT bool operator<(Entry lhs, Entry rhs);
+
+// Serializes entries to an "entries" array in a traced value.
+BASE_EXPORT std::unique_ptr<TracedValue> Serialize(const std::set<Entry>& dump);
+
+// Helper class to dump a snapshot of an |AllocationRegister| or other heap
+// bookkeeping structure into a |TracedValue|. This class is intended to be
+// used as a one-shot local instance on the stack.
+class BASE_EXPORT HeapDumpWriter {
+ public:
+  // The |stack_frame_deduplicator| and |type_name_deduplicator| are not owned.
+  // The heap dump writer assumes exclusive access to them during the lifetime
+  // of the dump writer. The heap dumps are broken down for allocations bigger
+  // than |breakdown_threshold_bytes|.
+  HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
+                 TypeNameDeduplicator* type_name_deduplicator,
+                 uint32_t breakdown_threshold_bytes);
+
+  ~HeapDumpWriter();
+
+  // Aggregates allocations to compute the total size of the heap, then breaks
+  // down the heap recursively. This produces the values that should be dumped
+  // in the "entries" array. The number of entries is kept reasonable because
+  // long tails are not included. Use |Serialize| to convert to a traced value.
+  const std::set<Entry>& Summarize(
+      const hash_map<AllocationContext, AllocationMetrics>& metrics_by_context);
+
+ private:
+  // Inserts an |Entry| for |Bucket| into |entries_|. Returns false if the
+  // entry was present before, true if it was not.
+  bool AddEntryForBucket(const Bucket& bucket);
+
+  // Recursively breaks down a bucket into smaller buckets and adds entries for
+  // the buckets worth dumping to |entries_|.
+  void BreakDown(const Bucket& bucket);
+
+  // The collection of entries that is filled by |Summarize|.
+  std::set<Entry> entries_;
+
+  // Helper for generating the |stackFrames| dictionary. Not owned, must outlive
+  // this heap dump writer instance.
+  StackFrameDeduplicator* const stack_frame_deduplicator_;
+
+  // Helper for converting type names to IDs. Not owned, must outlive this heap
+  // dump writer instance.
+  TypeNameDeduplicator* const type_name_deduplicator_;
+
+  // Minimum size of an allocation for which an allocation bucket will be
+  // broken down with children.
+  uint32_t breakdown_threshold_bytes_;
+
+  DISALLOW_COPY_AND_ASSIGN(HeapDumpWriter);
+};
+
+}  // namespace internal
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
diff --git a/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
new file mode 100644
index 0000000..49a2350
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
@@ -0,0 +1,135 @@
+// 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/heap_profiler_stack_frame_deduplicator.h"
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
+                                             int parent_frame_index)
+    : frame(frame), parent_frame_index(parent_frame_index) {}
+StackFrameDeduplicator::FrameNode::FrameNode(const FrameNode& other) = default;
+StackFrameDeduplicator::FrameNode::~FrameNode() {}
+
+StackFrameDeduplicator::StackFrameDeduplicator() {}
+StackFrameDeduplicator::~StackFrameDeduplicator() {}
+
+int StackFrameDeduplicator::Insert(const StackFrame* beginFrame,
+                                   const StackFrame* endFrame) {
+  int frame_index = -1;
+  std::map<StackFrame, int>* nodes = &roots_;
+
+  // Loop through the frames, early out when a frame is null.
+  for (const StackFrame* it = beginFrame; it != endFrame; it++) {
+    StackFrame frame = *it;
+
+    auto node = nodes->find(frame);
+    if (node == nodes->end()) {
+      // There is no tree node for this frame yet, create it. The parent node
+      // is the node associated with the previous frame.
+      FrameNode frame_node(frame, frame_index);
+
+      // The new frame node will be appended, so its index is the current size
+      // of the vector.
+      frame_index = static_cast<int>(frames_.size());
+
+      // Add the node to the trie so it will be found next time.
+      nodes->insert(std::make_pair(frame, frame_index));
+
+      // Append the node after modifying |nodes|, because the |frames_| vector
+      // might need to resize, and this invalidates the |nodes| pointer.
+      frames_.push_back(frame_node);
+    } else {
+      // A tree node for this frame exists. Look for the next one.
+      frame_index = node->second;
+    }
+
+    nodes = &frames_[frame_index].children;
+  }
+
+  return frame_index;
+}
+
+void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+  out->append("{");  // Begin the |stackFrames| dictionary.
+
+  int i = 0;
+  auto frame_node = begin();
+  auto it_end = end();
+  std::string stringify_buffer;
+
+  while (frame_node != it_end) {
+    // The |stackFrames| format is a dictionary, not an array, so the
+    // keys are stringified indices. Write the index manually, then use
+    // |TracedValue| to format the object. This is to avoid building the
+    // entire dictionary as a |TracedValue| in memory.
+    SStringPrintf(&stringify_buffer, "\"%d\":", i);
+    out->append(stringify_buffer);
+
+    std::unique_ptr<TracedValue> frame_node_value(new TracedValue);
+    const StackFrame& frame = frame_node->frame;
+    switch (frame.type) {
+      case StackFrame::Type::TRACE_EVENT_NAME:
+        frame_node_value->SetString(
+            "name", static_cast<const char*>(frame.value));
+        break;
+      case StackFrame::Type::THREAD_NAME:
+        SStringPrintf(&stringify_buffer,
+                      "[Thread: %s]",
+                      static_cast<const char*>(frame.value));
+        frame_node_value->SetString("name", stringify_buffer);
+        break;
+      case StackFrame::Type::PROGRAM_COUNTER:
+        SStringPrintf(&stringify_buffer,
+                      "pc:%" PRIxPTR,
+                      reinterpret_cast<uintptr_t>(frame.value));
+        frame_node_value->SetString("name", stringify_buffer);
+        break;
+    }
+    if (frame_node->parent_frame_index >= 0) {
+      SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
+      frame_node_value->SetString("parent", stringify_buffer);
+    }
+    frame_node_value->AppendAsTraceFormat(out);
+
+    i++;
+    frame_node++;
+
+    if (frame_node != it_end)
+      out->append(",");
+  }
+
+  out->append("}");  // End the |stackFrames| dictionary.
+}
+
+void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  // The sizes here are only estimates; they fail to take into account the
+  // overhead of the tree nodes for the map, but as an estimate this should be
+  // fine.
+  size_t maps_size = roots_.size() * sizeof(std::pair<StackFrame, int>);
+  size_t frames_allocated = frames_.capacity() * sizeof(FrameNode);
+  size_t frames_resident = frames_.size() * sizeof(FrameNode);
+
+  for (const FrameNode& node : frames_)
+    maps_size += node.children.size() * sizeof(std::pair<StackFrame, int>);
+
+  overhead->Add("StackFrameDeduplicator",
+                sizeof(StackFrameDeduplicator) + maps_size + frames_allocated,
+                sizeof(StackFrameDeduplicator) + maps_size + frames_resident);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator.h b/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator.h
new file mode 100644
index 0000000..4932534
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator.h
@@ -0,0 +1,79 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// A data structure that allows grouping a set of backtraces in a space-
+// efficient manner by creating a call tree and writing it as a set of (node,
+// parent) pairs. The tree nodes reference both parent and children. The parent
+// is referenced by index into |frames_|. The children are referenced via a map
+// of |StackFrame|s to index into |frames_|. So there is a trie for bottum-up
+// lookup of a backtrace for deduplication, and a tree for compact storage in
+// the trace log.
+class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
+ public:
+  // A node in the call tree.
+  struct FrameNode {
+    FrameNode(StackFrame frame, int parent_frame_index);
+    FrameNode(const FrameNode& other);
+    ~FrameNode();
+
+    StackFrame frame;
+
+    // The index of the parent stack frame in |frames_|, or -1 if there is no
+    // parent frame (when it is at the bottom of the call stack).
+    int parent_frame_index;
+
+    // Indices into |frames_| of frames called from the current frame.
+    std::map<StackFrame, int> children;
+  };
+
+  using ConstIterator = std::vector<FrameNode>::const_iterator;
+
+  StackFrameDeduplicator();
+  ~StackFrameDeduplicator() override;
+
+  // Inserts a backtrace where |beginFrame| is a pointer to the bottom frame
+  // (e.g. main) and |endFrame| is a pointer past the top frame (most recently
+  // called function), and returns the index of its leaf node in |frames_|.
+  // Returns -1 if the backtrace is empty.
+  int Insert(const StackFrame* beginFrame, const StackFrame* endFrame);
+
+  // Iterators over the frame nodes in the call tree.
+  ConstIterator begin() const { return frames_.begin(); }
+  ConstIterator end() const { return frames_.end(); }
+
+  // Writes the |stackFrames| dictionary as defined in https://goo.gl/GerkV8 to
+  // the trace log.
+  void AppendAsTraceFormat(std::string* out) const override;
+
+  // Estimates memory overhead including |sizeof(StackFrameDeduplicator)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+  std::map<StackFrame, int> roots_;
+  std::vector<FrameNode> frames_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackFrameDeduplicator);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
diff --git a/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
new file mode 100644
index 0000000..2215ede
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
@@ -0,0 +1,152 @@
+// 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/heap_profiler_stack_frame_deduplicator.h"
+
+#include <iterator>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+StackFrame kBrowserMain = StackFrame::FromTraceEventName("BrowserMain");
+StackFrame kRendererMain = StackFrame::FromTraceEventName("RendererMain");
+StackFrame kCreateWidget = StackFrame::FromTraceEventName("CreateWidget");
+StackFrame kInitialize = StackFrame::FromTraceEventName("Initialize");
+StackFrame kMalloc = StackFrame::FromTraceEventName("malloc");
+
+TEST(StackFrameDeduplicatorTest, SingleBacktrace) {
+  StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  //     malloc [2]
+
+  std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
+  ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kMalloc, (iter + 2)->frame);
+  ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(iter + 3, dedup->end());
+}
+
+TEST(StackFrameDeduplicatorTest, SingleBacktraceWithNull) {
+  StackFrame null_frame = StackFrame::FromTraceEventName(nullptr);
+  StackFrame bt[] = {kBrowserMain, null_frame, kMalloc};
+
+  // Deduplicator doesn't care about what's inside StackFrames,
+  // and handles nullptr StackFrame values as any other.
+  //
+  // So the call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   (null) [1]
+  //     malloc [2]
+
+  std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
+  ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(null_frame, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kMalloc, (iter + 2)->frame);
+  ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(iter + 3, dedup->end());
+}
+
+// Test that there can be different call trees (there can be multiple bottom
+// frames). Also verify that frames with the same name but a different caller
+// are represented as distinct nodes.
+TEST(StackFrameDeduplicatorTest, MultipleRoots) {
+  StackFrame bt0[] = {kBrowserMain, kCreateWidget};
+  StackFrame bt1[] = {kRendererMain, kCreateWidget};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  // RendererMain [2]
+  //   CreateWidget [3]
+  //
+  // Note that there will be two instances of CreateWidget,
+  // with different parents.
+
+  std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
+  ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+  ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1)));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kRendererMain, (iter + 2)->frame);
+  ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
+  ASSERT_EQ(2, (iter + 3)->parent_frame_index);
+
+  ASSERT_EQ(iter + 4, dedup->end());
+}
+
+TEST(StackFrameDeduplicatorTest, Deduplication) {
+  StackFrame bt0[] = {kBrowserMain, kCreateWidget};
+  StackFrame bt1[] = {kBrowserMain, kInitialize};
+
+  // The call tree should look like this (index in brackets).
+  //
+  // BrowserMain [0]
+  //   CreateWidget [1]
+  //   Initialize [2]
+  //
+  // Note that BrowserMain will be re-used.
+
+  std::unique_ptr<StackFrameDeduplicator> dedup(new StackFrameDeduplicator);
+  ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+  ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
+
+  auto iter = dedup->begin();
+  ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+  ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+  ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+  ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+  ASSERT_EQ(kInitialize, (iter + 2)->frame);
+  ASSERT_EQ(0, (iter + 2)->parent_frame_index);
+
+  ASSERT_EQ(iter + 3, dedup->end());
+
+  // Inserting the same backtrace again should return the index of the existing
+  // node.
+  ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+  ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
+  ASSERT_EQ(dedup->begin() + 3, dedup->end());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_type_name_deduplicator.cc b/libchrome/base/trace_event/heap_profiler_type_name_deduplicator.cc
new file mode 100644
index 0000000..055f86a
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_type_name_deduplicator.cc
@@ -0,0 +1,107 @@
+// 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/heap_profiler_type_name_deduplicator.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string>
+#include <utility>
+
+#include "base/json/string_escape.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Extract directory name if |type_name| was file name. Otherwise, return
+// |type_name|.
+StringPiece ExtractDirNameFromFileName(const char* type_name) {
+  StringPiece result(type_name);
+  size_t last_seperator = result.find_last_of("\\/");
+
+  // If |type_name| was a not a file path, the seperator will not be found, so
+  // the whole type name is returned.
+  if (last_seperator == StringPiece::npos)
+    return result;
+
+  // Remove the file name from the path.
+  result.remove_suffix(result.length() - last_seperator);
+
+  // Remove the parent directory references.
+  const char kParentDirectory[] = "..";
+  const size_t kParentDirectoryLength = 3; // '../' or '..\'.
+  while (result.starts_with(kParentDirectory)) {
+    result.remove_prefix(kParentDirectoryLength);
+  }
+  return result;
+}
+
+}  // namespace
+
+TypeNameDeduplicator::TypeNameDeduplicator() {
+  // A null pointer has type ID 0 ("unknown type");
+  type_ids_.insert(std::make_pair(nullptr, 0));
+}
+
+TypeNameDeduplicator::~TypeNameDeduplicator() {}
+
+int TypeNameDeduplicator::Insert(const char* type_name) {
+  auto result = type_ids_.insert(std::make_pair(type_name, 0));
+  auto& elem = result.first;
+  bool did_not_exist_before = result.second;
+
+  if (did_not_exist_before) {
+    // The type IDs are assigned sequentially and they are zero-based, so
+    // |size() - 1| is the ID of the new element.
+    elem->second = static_cast<int>(type_ids_.size() - 1);
+  }
+
+  return elem->second;
+}
+
+void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+  out->append("{");  // Begin the type names dictionary.
+
+  auto it = type_ids_.begin();
+  std::string buffer;
+
+  // Write the first entry manually; the null pointer must not be dereferenced.
+  // (The first entry is the null pointer because a |std::map| is ordered.)
+  it++;
+  out->append("\"0\":\"[unknown]\"");
+
+  for (; it != type_ids_.end(); it++) {
+    // Type IDs in the trace are strings, write them as stringified keys of
+    // a dictionary.
+    SStringPrintf(&buffer, ",\"%d\":", it->second);
+
+    // TODO(ssid): crbug.com/594803 the type name is misused for file name in
+    // some cases.
+    StringPiece type_info = ExtractDirNameFromFileName(it->first);
+
+    // |EscapeJSONString| appends, it does not overwrite |buffer|.
+    bool put_in_quotes = true;
+    EscapeJSONString(type_info, put_in_quotes, &buffer);
+    out->append(buffer);
+  }
+
+  out->append("}");  // End the type names dictionary.
+}
+
+void TypeNameDeduplicator::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  // The size here is only an estimate; it fails to take into account the size
+  // of the tree nodes for the map, but as an estimate this should be fine.
+  size_t map_size = type_ids_.size() * sizeof(std::pair<const char*, int>);
+
+  overhead->Add("TypeNameDeduplicator",
+                sizeof(TypeNameDeduplicator) + map_size);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/heap_profiler_type_name_deduplicator.h b/libchrome/base/trace_event/heap_profiler_type_name_deduplicator.h
new file mode 100644
index 0000000..2d26c73
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_type_name_deduplicator.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_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// Data structure that assigns a unique numeric ID to |const char*|s.
+class BASE_EXPORT TypeNameDeduplicator : public ConvertableToTraceFormat {
+ public:
+  TypeNameDeduplicator();
+  ~TypeNameDeduplicator() override;
+
+  // Inserts a type name and returns its ID.
+  int Insert(const char* type_name);
+
+  // Writes the type ID -> type name mapping to the trace log.
+  void AppendAsTraceFormat(std::string* out) const override;
+
+  // Estimates memory overhead including |sizeof(TypeNameDeduplicator)|.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+  // Map from type name to type ID.
+  std::map<const char*, int> type_ids_;
+
+  DISALLOW_COPY_AND_ASSIGN(TypeNameDeduplicator);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
diff --git a/libchrome/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc b/libchrome/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
new file mode 100644
index 0000000..b2e681a
--- /dev/null
+++ b/libchrome/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
@@ -0,0 +1,96 @@
+// 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 <memory>
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kInt[] = "int";
+const char kBool[] = "bool";
+const char kString[] = "string";
+const char kNeedsEscape[] = "\"quotes\"";
+
+#if defined(OS_POSIX)
+const char kTaskFileName[] = "../../base/trace_event/trace_log.cc";
+const char kTaskPath[] = "base/trace_event";
+#else
+const char kTaskFileName[] = "..\\..\\base\\memory\\memory_win.cc";
+const char kTaskPath[] = "base\\memory";
+#endif
+
+std::unique_ptr<Value> DumpAndReadBack(
+    const TypeNameDeduplicator& deduplicator) {
+  std::string json;
+  deduplicator.AppendAsTraceFormat(&json);
+  return JSONReader::Read(json);
+}
+
+// Inserts a single type name into a new TypeNameDeduplicator instance and
+// checks if the value gets inserted and the exported value for |type_name| is
+// the same as |expected_value|.
+void TestInsertTypeAndReadback(const char* type_name,
+                               const char* expected_value) {
+  std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator);
+  ASSERT_EQ(1, dedup->Insert(type_name));
+
+  std::unique_ptr<Value> type_names = DumpAndReadBack(*dedup);
+  ASSERT_NE(nullptr, type_names);
+
+  const DictionaryValue* dictionary;
+  ASSERT_TRUE(type_names->GetAsDictionary(&dictionary));
+
+  // When the type name was inserted, it got ID 1. The exported key "1"
+  // should be equal to |expected_value|.
+  std::string value;
+  ASSERT_TRUE(dictionary->GetString("1", &value));
+  ASSERT_EQ(expected_value, value);
+}
+
+}  // namespace
+
+TEST(TypeNameDeduplicatorTest, Deduplication) {
+  // The type IDs should be like this:
+  // 0: [unknown]
+  // 1: int
+  // 2: bool
+  // 3: string
+
+  std::unique_ptr<TypeNameDeduplicator> dedup(new TypeNameDeduplicator);
+  ASSERT_EQ(1, dedup->Insert(kInt));
+  ASSERT_EQ(2, dedup->Insert(kBool));
+  ASSERT_EQ(3, dedup->Insert(kString));
+
+  // Inserting again should return the same IDs.
+  ASSERT_EQ(2, dedup->Insert(kBool));
+  ASSERT_EQ(1, dedup->Insert(kInt));
+  ASSERT_EQ(3, dedup->Insert(kString));
+
+  // A null pointer should yield type ID 0.
+  ASSERT_EQ(0, dedup->Insert(nullptr));
+}
+
+TEST(TypeNameDeduplicatorTest, EscapeTypeName) {
+  // Reading json should not fail, because the type name should have been
+  // escaped properly and exported value should contain quotes.
+  TestInsertTypeAndReadback(kNeedsEscape, kNeedsEscape);
+}
+
+TEST(TypeNameDeduplicatorTest, TestExtractFileName) {
+  // The exported value for passed file name should be the folders in the path.
+  TestInsertTypeAndReadback(kTaskFileName, kTaskPath);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/malloc_dump_provider.cc b/libchrome/base/trace_event/malloc_dump_provider.cc
new file mode 100644
index 0000000..c3d3258
--- /dev/null
+++ b/libchrome/base/trace_event/malloc_dump_provider.cc
@@ -0,0 +1,258 @@
+// 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 <stddef.h>
+
+#include "base/allocator/allocator_extension.h"
+#include "base/allocator/allocator_shim.h"
+#include "base/allocator/features.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_allocation_register.h"
+#include "base/trace_event/heap_profiler_heap_dump_writer.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_MACOSX)
+#include <malloc/malloc.h>
+#else
+#include <malloc.h>
+#endif
+
+namespace base {
+namespace trace_event {
+
+#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
+namespace {
+
+using allocator::AllocatorDispatch;
+
+void* HookAlloc(const AllocatorDispatch* self, size_t size) {
+  const AllocatorDispatch* const next = self->next;
+  void* ptr = next->alloc_function(next, size);
+  if (ptr)
+    MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
+  return ptr;
+}
+
+void* HookZeroInitAlloc(const AllocatorDispatch* self, size_t n, size_t size) {
+  const AllocatorDispatch* const next = self->next;
+  void* ptr = next->alloc_zero_initialized_function(next, n, size);
+  if (ptr)
+    MallocDumpProvider::GetInstance()->InsertAllocation(ptr, n * size);
+  return ptr;
+}
+
+void* HookllocAligned(const AllocatorDispatch* self,
+                      size_t alignment,
+                      size_t size) {
+  const AllocatorDispatch* const next = self->next;
+  void* ptr = next->alloc_aligned_function(next, alignment, size);
+  if (ptr)
+    MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
+  return ptr;
+}
+
+void* HookRealloc(const AllocatorDispatch* self, void* address, size_t size) {
+  const AllocatorDispatch* const next = self->next;
+  void* ptr = next->realloc_function(next, address, size);
+  MallocDumpProvider::GetInstance()->RemoveAllocation(address);
+  if (size > 0)  // realloc(size == 0) means free().
+    MallocDumpProvider::GetInstance()->InsertAllocation(ptr, size);
+  return ptr;
+}
+
+void HookFree(const AllocatorDispatch* self, void* address) {
+  if (address)
+    MallocDumpProvider::GetInstance()->RemoveAllocation(address);
+  const AllocatorDispatch* const next = self->next;
+  next->free_function(next, address);
+}
+
+AllocatorDispatch g_allocator_hooks = {
+    &HookAlloc,         /* alloc_function */
+    &HookZeroInitAlloc, /* alloc_zero_initialized_function */
+    &HookllocAligned,   /* alloc_aligned_function */
+    &HookRealloc,       /* realloc_function */
+    &HookFree,          /* free_function */
+    nullptr,            /* next */
+};
+
+}  // namespace
+#endif  // BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
+
+// static
+const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects";
+
+// static
+MallocDumpProvider* MallocDumpProvider::GetInstance() {
+  return Singleton<MallocDumpProvider,
+                   LeakySingletonTraits<MallocDumpProvider>>::get();
+}
+
+MallocDumpProvider::MallocDumpProvider()
+    : heap_profiler_enabled_(false), tid_dumping_heap_(kInvalidThreadId) {}
+
+MallocDumpProvider::~MallocDumpProvider() {}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
+                                      ProcessMemoryDump* pmd) {
+  size_t total_virtual_size = 0;
+  size_t resident_size = 0;
+  size_t allocated_objects_size = 0;
+#if defined(USE_TCMALLOC)
+  bool res =
+      allocator::GetNumericProperty("generic.heap_size", &total_virtual_size);
+  DCHECK(res);
+  res = allocator::GetNumericProperty("generic.total_physical_bytes",
+                                      &resident_size);
+  DCHECK(res);
+  res = allocator::GetNumericProperty("generic.current_allocated_bytes",
+                                      &allocated_objects_size);
+  DCHECK(res);
+#elif defined(OS_MACOSX) || defined(OS_IOS)
+  malloc_statistics_t stats;
+  memset(&stats, 0, sizeof(stats));
+  malloc_zone_statistics(nullptr, &stats);
+  total_virtual_size = stats.size_allocated;
+  allocated_objects_size = stats.size_in_use;
+
+  // The resident size is approximated to the max size in use, which would count
+  // the total size of all regions other than the free bytes at the end of each
+  // region. In each allocation region the allocations are rounded off to a
+  // fixed quantum, so the excess region will not be resident.
+  // See crrev.com/1531463004 for detailed explanation.
+  resident_size = stats.max_size_in_use;
+#else
+  struct mallinfo info = mallinfo();
+  DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
+
+  // 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.
+  total_virtual_size = info.arena + info.hblkhd;
+  resident_size = info.uordblks;
+  allocated_objects_size = info.uordblks;
+#endif
+
+  MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
+  outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes,
+                        total_virtual_size);
+  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes, resident_size);
+
+  // Total allocated space is given by |uordblks|.
+  MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects);
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        allocated_objects_size);
+
+  if (resident_size - allocated_objects_size > 0) {
+    // Explicitly specify why is extra memory resident. In tcmalloc it accounts
+    // for free lists and caches. In mac and ios it accounts for the
+    // fragmentation and metadata.
+    MemoryAllocatorDump* other_dump =
+        pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches");
+    other_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                          MemoryAllocatorDump::kUnitsBytes,
+                          resident_size - allocated_objects_size);
+  }
+
+  // Heap profiler dumps.
+  if (!heap_profiler_enabled_)
+    return true;
+
+  // The dumps of the heap profiler should be created only when heap profiling
+  // was enabled (--enable-heap-profiling) AND a DETAILED dump is requested.
+  // However, when enabled, the overhead of the heap profiler should be always
+  // reported to avoid oscillations of the malloc total in LIGHT dumps.
+
+  tid_dumping_heap_ = PlatformThread::CurrentId();
+  // At this point the Insert/RemoveAllocation hooks will ignore this thread.
+  // Enclosing all the temporariy data structures in a scope, so that the heap
+  // profiler does not see unabalanced malloc/free calls from these containers.
+  {
+    TraceEventMemoryOverhead overhead;
+    hash_map<AllocationContext, AllocationMetrics> metrics_by_context;
+    {
+      AutoLock lock(allocation_register_lock_);
+      if (allocation_register_) {
+        if (args.level_of_detail == MemoryDumpLevelOfDetail::DETAILED) {
+          for (const auto& alloc_size : *allocation_register_) {
+            AllocationMetrics& metrics = metrics_by_context[alloc_size.context];
+            metrics.size += alloc_size.size;
+            metrics.count++;
+          }
+        }
+        allocation_register_->EstimateTraceMemoryOverhead(&overhead);
+      }
+    }  // lock(allocation_register_lock_)
+    pmd->DumpHeapUsage(metrics_by_context, overhead, "malloc");
+  }
+  tid_dumping_heap_ = kInvalidThreadId;
+
+  return true;
+}
+
+void MallocDumpProvider::OnHeapProfilingEnabled(bool enabled) {
+#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
+  if (enabled) {
+    {
+      AutoLock lock(allocation_register_lock_);
+      allocation_register_.reset(new AllocationRegister());
+    }
+    allocator::InsertAllocatorDispatch(&g_allocator_hooks);
+  } else {
+    AutoLock lock(allocation_register_lock_);
+    allocation_register_.reset();
+    // Insert/RemoveAllocation below will no-op if the register is torn down.
+    // Once disabled, heap profiling will not re-enabled anymore for the
+    // lifetime of the process.
+  }
+#endif
+  heap_profiler_enabled_ = enabled;
+}
+
+void MallocDumpProvider::InsertAllocation(void* address, size_t size) {
+  // CurrentId() can be a slow operation (crbug.com/497226). This apparently
+  // redundant condition short circuits the CurrentID() calls when unnecessary.
+  if (tid_dumping_heap_ != kInvalidThreadId &&
+      tid_dumping_heap_ == PlatformThread::CurrentId())
+    return;
+
+  // AllocationContextTracker will return nullptr when called re-reentrantly.
+  // This is the case of GetInstanceForCurrentThread() being called for the
+  // first time, which causes a new() inside the tracker which re-enters the
+  // heap profiler, in which case we just want to early out.
+  auto* tracker = AllocationContextTracker::GetInstanceForCurrentThread();
+  if (!tracker)
+    return;
+  AllocationContext context = tracker->GetContextSnapshot();
+
+  AutoLock lock(allocation_register_lock_);
+  if (!allocation_register_)
+    return;
+
+  allocation_register_->Insert(address, size, context);
+}
+
+void MallocDumpProvider::RemoveAllocation(void* address) {
+  // No re-entrancy is expected here as none of the calls below should
+  // cause a free()-s (|allocation_register_| does its own heap management).
+  if (tid_dumping_heap_ != kInvalidThreadId &&
+      tid_dumping_heap_ == PlatformThread::CurrentId())
+    return;
+  AutoLock lock(allocation_register_lock_);
+  if (!allocation_register_)
+    return;
+  allocation_register_->Remove(address);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/malloc_dump_provider.h b/libchrome/base/trace_event/malloc_dump_provider.h
new file mode 100644
index 0000000..4746cf5
--- /dev/null
+++ b/libchrome/base/trace_event/malloc_dump_provider.h
@@ -0,0 +1,69 @@
+// 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 <memory>
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX) || defined(OS_ANDROID) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
+#define MALLOC_MEMORY_TRACING_SUPPORTED
+#endif
+
+namespace base {
+namespace trace_event {
+
+class AllocationRegister;
+
+// 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(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override;
+
+  void OnHeapProfilingEnabled(bool enabled) override;
+
+  // For heap profiling.
+  void InsertAllocation(void* address, size_t size);
+  void RemoveAllocation(void* address);
+
+ private:
+  friend struct DefaultSingletonTraits<MallocDumpProvider>;
+
+  MallocDumpProvider();
+  ~MallocDumpProvider() override;
+
+  // For heap profiling.
+  bool heap_profiler_enabled_;
+  std::unique_ptr<AllocationRegister> allocation_register_;
+  Lock allocation_register_lock_;
+
+  // When in OnMemoryDump(), this contains the current thread ID.
+  // This is to prevent re-entrancy in the heap profiler when the heap dump
+  // generation is malloc/new-ing for its own bookeeping data structures.
+  PlatformThreadId tid_dumping_heap_;
+
+  DISALLOW_COPY_AND_ASSIGN(MallocDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
diff --git a/libchrome/base/trace_event/memory_allocator_dump.cc b/libchrome/base/trace_event/memory_allocator_dump.cc
new file mode 100644
index 0000000..7583763
--- /dev/null
+++ b/libchrome/base/trace_event/memory_allocator_dump.cc
@@ -0,0 +1,107 @@
+// 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::kNameObjectCount[] = "object_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),
+      flags_(Flags::DEFAULT) {
+  // 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() != '/');
+}
+
+// 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_t 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) {
+  // String attributes are disabled in background mode.
+  if (process_memory_dump_->dump_args().level_of_detail ==
+      MemoryDumpLevelOfDetail::BACKGROUND) {
+    NOTREACHED();
+    return;
+  }
+
+  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_);
+  if (flags_)
+    value->SetInteger("flags", flags_);
+  value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/memory_allocator_dump.h b/libchrome/base/trace_event/memory_allocator_dump.h
new file mode 100644
index 0000000..7d10236
--- /dev/null
+++ b/libchrome/base/trace_event/memory_allocator_dump.h
@@ -0,0 +1,110 @@
+// 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 <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.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:
+  enum Flags {
+    DEFAULT = 0,
+
+    // A dump marked weak will be discarded by TraceViewer.
+    WEAK = 1 << 0,
+  };
+
+  // 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|s for the AddScalar and AddString() methods.
+  static const char kNameSize[];          // To represent allocated space.
+  static const char kNameObjectCount[];   // To represent number of objects.
+
+  // Standard attribute |unit|s for the AddScalar and AddString() methods.
+  static const char kUnitsBytes[];    // Unit name to represent bytes.
+  static const char kUnitsObjects[];  // Unit name to represent #objects.
+
+  // Constants used only internally and by tests.
+  static const char kTypeScalar[];  // Type name for scalar attributes.
+  static const char kTypeString[];  // Type name for string attributes.
+
+  // Setters for scalar attributes. Some examples:
+  // - "size" column (all dumps are expected to have at least this one):
+  //     AddScalar(kNameSize, kUnitsBytes, 1234);
+  // - Some extra-column reporting internal details of the subsystem:
+  //    AddScalar("number_of_freelist_entires", kUnitsObjects, 42)
+  // - Other informational column (will not be auto-added in the UI)
+  //    AddScalarF("kittens_ratio", "ratio", 42.0f)
+  void AddScalar(const char* name, const char* units, uint64_t value);
+  void AddScalarF(const char* name, const char* units, double value);
+  void AddString(const char* name, const char* units, const std::string& value);
+
+  // Absolute name, unique within the scope of an entire ProcessMemoryDump.
+  const std::string& absolute_name() const { return absolute_name_; }
+
+  // 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_;
+  }
+
+  // Use enum Flags to set values.
+  void set_flags(int flags) { flags_ |= flags; }
+  void clear_flags(int flags) { flags_ &= ~flags; }
+  int flags() { return flags_; }
+
+  // |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).
+  std::unique_ptr<TracedValue> attributes_;
+  MemoryAllocatorDumpGuid guid_;
+  int flags_;  // See enum Flags.
+
+  // 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/libchrome/base/trace_event/memory_allocator_dump_guid.cc b/libchrome/base/trace_event/memory_allocator_dump_guid.cc
new file mode 100644
index 0000000..bf4389a
--- /dev/null
+++ b/libchrome/base/trace_event/memory_allocator_dump_guid.cc
@@ -0,0 +1,38 @@
+// 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/sha1.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+uint64_t HashString(const std::string& str) {
+  uint64_t hash[(kSHA1Length + sizeof(uint64_t) - 1) / sizeof(uint64_t)] = {0};
+  SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.data()), str.size(),
+                reinterpret_cast<unsigned char*>(hash));
+  return hash[0];
+}
+}  // namespace
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64_t guid) : guid_(guid) {}
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid()
+    : MemoryAllocatorDumpGuid(0u) {
+}
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(const std::string& guid_str)
+    : MemoryAllocatorDumpGuid(HashString(guid_str)) {
+}
+
+std::string MemoryAllocatorDumpGuid::ToString() const {
+  return StringPrintf("%" PRIx64, guid_);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/memory_allocator_dump_guid.h b/libchrome/base/trace_event/memory_allocator_dump_guid.h
new file mode 100644
index 0000000..b6472c6
--- /dev/null
+++ b/libchrome/base/trace_event/memory_allocator_dump_guid.h
@@ -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.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT MemoryAllocatorDumpGuid {
+ public:
+  MemoryAllocatorDumpGuid();
+  explicit MemoryAllocatorDumpGuid(uint64_t 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);
+
+  uint64_t ToUint64() const { return guid_; }
+
+  // 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_t guid_;
+
+  // Deliberately copy-able.
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
diff --git a/libchrome/base/trace_event/memory_allocator_dump_unittest.cc b/libchrome/base/trace_event/memory_allocator_dump_unittest.cc
new file mode 100644
index 0000000..1bf9715
--- /dev/null
+++ b/libchrome/base/trace_event/memory_allocator_dump_unittest.cc
@@ -0,0 +1,190 @@
+// 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 <stdint.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 "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
+ public:
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    ProcessMemoryDump* pmd) override {
+    MemoryAllocatorDump* root_heap =
+        pmd->CreateAllocatorDump("foobar_allocator");
+
+    root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
+                         MemoryAllocatorDump::kUnitsBytes, 4096);
+    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectCount,
+                         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::kNameObjectCount,
+                        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;
+  }
+};
+
+std::unique_ptr<Value> CheckAttribute(const MemoryAllocatorDump* dump,
+                                      const std::string& name,
+                                      const char* expected_type,
+                                      const char* expected_units) {
+  std::unique_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() : std::unique_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_t 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) {
+  std::unique_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;
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
+  ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args);
+
+  fmadp.OnMemoryDump(dump_args, &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::kNameObjectCount,
+              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::kNameObjectCount,
+              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::kNameObjectCount));
+
+  // Check that the AsValueInfo doesn't hit any DCHECK.
+  std::unique_ptr<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;
+  MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
+  ProcessMemoryDump pmd(new MemoryDumpSessionState, dump_args);
+  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/libchrome/base/trace_event/memory_dump_manager.cc b/libchrome/base/trace_event/memory_dump_manager.cc
new file mode 100644
index 0000000..eed070a
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_manager.cc
@@ -0,0 +1,883 @@
+// 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 <utility>
+
+#include "base/atomic_sequence_num.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/debugging_flags.h"
+#include "base/debug/stack_trace.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/heap_profiler.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/malloc_dump_provider.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/memory_infra_background_whitelist.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#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 {
+
+const int kTraceEventNumArgs = 1;
+const char* kTraceEventArgNames[] = {"dumps"};
+const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+
+StaticAtomicSequenceNumber g_next_guid;
+MemoryDumpManager* g_instance_for_testing = nullptr;
+
+// Callback wrapper to hook upon the completion of RequestGlobalDump() and
+// inject trace markers.
+void OnGlobalDumpDone(MemoryDumpCallback wrapped_callback,
+                      uint64_t dump_guid,
+                      bool success) {
+  TRACE_EVENT_NESTABLE_ASYNC_END1(
+      MemoryDumpManager::kTraceCategory, "GlobalMemoryDump",
+      TRACE_ID_MANGLE(dump_guid), "success", success);
+
+  if (!wrapped_callback.is_null()) {
+    wrapped_callback.Run(dump_guid, success);
+    wrapped_callback.Reset();
+  }
+}
+
+// Proxy class which wraps a ConvertableToTraceFormat owned by the
+// |session_state| into a proxy object that can be added to the trace event log.
+// This is to solve the problem that the MemoryDumpSessionState is refcounted
+// but the tracing subsystem wants a std::unique_ptr<ConvertableToTraceFormat>.
+template <typename T>
+struct SessionStateConvertableProxy : public ConvertableToTraceFormat {
+  using GetterFunctPtr = T* (MemoryDumpSessionState::*)() const;
+
+  SessionStateConvertableProxy(
+      scoped_refptr<MemoryDumpSessionState> session_state,
+      GetterFunctPtr getter_function)
+      : session_state(session_state), getter_function(getter_function) {}
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    return (session_state.get()->*getter_function)()->AppendAsTraceFormat(out);
+  }
+
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    return (session_state.get()->*getter_function)()
+        ->EstimateTraceMemoryOverhead(overhead);
+  }
+
+  scoped_refptr<MemoryDumpSessionState> session_state;
+  GetterFunctPtr const getter_function;
+};
+
+}  // namespace
+
+// static
+const char* const MemoryDumpManager::kTraceCategory =
+    TRACE_DISABLED_BY_DEFAULT("memory-infra");
+
+// static
+const char* const MemoryDumpManager::kLogPrefix = "Memory-infra dump";
+
+// static
+const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
+
+// static
+const uint64_t MemoryDumpManager::kInvalidTracingProcessId = 0;
+
+// static
+const char* const MemoryDumpManager::kSystemAllocatorPoolName =
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
+    MallocDumpProvider::kAllocatedObjects;
+#elif defined(OS_WIN)
+    WinHeapDumpProvider::kAllocatedObjects;
+#else
+    nullptr;
+#endif
+
+// 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) {
+  g_instance_for_testing = instance;
+}
+
+MemoryDumpManager::MemoryDumpManager()
+    : delegate_(nullptr),
+      is_coordinator_(false),
+      memory_tracing_enabled_(0),
+      tracing_process_id_(kInvalidTracingProcessId),
+      dumper_registrations_ignored_for_testing_(false),
+      heap_profiling_enabled_(false) {
+  g_next_guid.GetNext();  // Make sure that first guid is not zero.
+
+  // At this point the command line may not be initialized but we try to
+  // enable the heap profiler to capture allocations as soon as possible.
+  EnableHeapProfilingIfNeeded();
+}
+
+MemoryDumpManager::~MemoryDumpManager() {
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+void MemoryDumpManager::EnableHeapProfilingIfNeeded() {
+  if (heap_profiling_enabled_)
+    return;
+
+  if (!CommandLine::InitializedForCurrentProcess() ||
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableHeapProfiling))
+    return;
+
+  std::string profiling_mode = CommandLine::ForCurrentProcess()
+      ->GetSwitchValueASCII(switches::kEnableHeapProfiling);
+  if (profiling_mode == "") {
+    AllocationContextTracker::SetCaptureMode(
+        AllocationContextTracker::CaptureMode::PSEUDO_STACK);
+  }
+  else if (profiling_mode == switches::kEnableHeapProfilingModeNative) {
+#if HAVE_TRACE_STACK_FRAME_POINTERS && \
+    (BUILDFLAG(ENABLE_PROFILING) || !defined(NDEBUG))
+    // We need frame pointers for native tracing to work, and they are
+    // enabled in profiling and debug builds.
+    AllocationContextTracker::SetCaptureMode(
+        AllocationContextTracker::CaptureMode::NATIVE_STACK);
+#else
+    CHECK(false) << "'" << profiling_mode << "' mode for "
+                 << switches::kEnableHeapProfiling << " flag is not supported "
+                 << "for this platform / build type.";
+#endif
+  } else {
+    CHECK(false) << "Invalid mode '" << profiling_mode << "' for "
+               << switches::kEnableHeapProfiling << " flag.";
+  }
+
+  for (auto mdp : dump_providers_)
+    mdp->dump_provider->OnHeapProfilingEnabled(true);
+  heap_profiling_enabled_ = true;
+}
+
+void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
+                                   bool is_coordinator) {
+  {
+    AutoLock lock(lock_);
+    DCHECK(delegate);
+    DCHECK(!delegate_);
+    delegate_ = delegate;
+    is_coordinator_ = is_coordinator;
+    EnableHeapProfilingIfNeeded();
+  }
+
+// Enable the core dump providers.
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
+  RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr);
+#endif
+
+#if defined(OS_ANDROID)
+  RegisterDumpProvider(JavaHeapDumpProvider::GetInstance(), "JavaHeap",
+                       nullptr);
+#endif
+
+#if defined(OS_WIN)
+  RegisterDumpProvider(WinHeapDumpProvider::GetInstance(), "WinHeap", nullptr);
+#endif
+
+  // If tracing was enabled before initializing MemoryDumpManager, we missed the
+  // OnTraceLogEnabled() event. Synthetize it so we can late-join the party.
+  bool is_tracing_already_enabled = TraceLog::GetInstance()->IsEnabled();
+  TRACE_EVENT0(kTraceCategory, "init");  // Add to trace-viewer category list.
+  TraceLog::GetInstance()->AddEnabledStateObserver(this);
+  if (is_tracing_already_enabled)
+    OnTraceLogEnabled();
+}
+
+void MemoryDumpManager::RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    const char* name,
+    scoped_refptr<SingleThreadTaskRunner> task_runner,
+    MemoryDumpProvider::Options options) {
+  options.dumps_on_single_thread_task_runner = true;
+  RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
+}
+
+void MemoryDumpManager::RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    const char* name,
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  // Set |dumps_on_single_thread_task_runner| to true because all providers
+  // without task runner are run on dump thread.
+  MemoryDumpProvider::Options options;
+  options.dumps_on_single_thread_task_runner = true;
+  RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
+}
+
+void MemoryDumpManager::RegisterDumpProviderWithSequencedTaskRunner(
+    MemoryDumpProvider* mdp,
+    const char* name,
+    scoped_refptr<SequencedTaskRunner> task_runner,
+    MemoryDumpProvider::Options options) {
+  DCHECK(task_runner);
+  options.dumps_on_single_thread_task_runner = false;
+  RegisterDumpProviderInternal(mdp, name, std::move(task_runner), options);
+}
+
+void MemoryDumpManager::RegisterDumpProviderInternal(
+    MemoryDumpProvider* mdp,
+    const char* name,
+    scoped_refptr<SequencedTaskRunner> task_runner,
+    const MemoryDumpProvider::Options& options) {
+  if (dumper_registrations_ignored_for_testing_)
+    return;
+
+  bool whitelisted_for_background_mode = IsMemoryDumpProviderWhitelisted(name);
+  scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
+      new MemoryDumpProviderInfo(mdp, name, std::move(task_runner), options,
+                                 whitelisted_for_background_mode);
+
+  {
+    AutoLock lock(lock_);
+    bool already_registered = !dump_providers_.insert(mdpinfo).second;
+    // This actually happens in some tests which don't have a clean tear-down
+    // path for RenderThreadImpl::Init().
+    if (already_registered)
+      return;
+  }
+
+  if (heap_profiling_enabled_)
+    mdp->OnHeapProfilingEnabled(true);
+}
+
+void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+  UnregisterDumpProviderInternal(mdp, false /* delete_async */);
+}
+
+void MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon(
+    std::unique_ptr<MemoryDumpProvider> mdp) {
+  UnregisterDumpProviderInternal(mdp.release(), true /* delete_async */);
+}
+
+void MemoryDumpManager::UnregisterDumpProviderInternal(
+    MemoryDumpProvider* mdp,
+    bool take_mdp_ownership_and_delete_async) {
+  std::unique_ptr<MemoryDumpProvider> owned_mdp;
+  if (take_mdp_ownership_and_delete_async)
+    owned_mdp.reset(mdp);
+
+  AutoLock lock(lock_);
+
+  auto mdp_iter = dump_providers_.begin();
+  for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
+    if ((*mdp_iter)->dump_provider == mdp)
+      break;
+  }
+
+  if (mdp_iter == dump_providers_.end())
+    return;  // Not registered / already unregistered.
+
+  if (take_mdp_ownership_and_delete_async) {
+    // The MDP will be deleted whenever the MDPInfo struct will, that is either:
+    // - At the end of this function, if no dump is in progress.
+    // - Either in SetupNextMemoryDump() or InvokeOnMemoryDump() when MDPInfo is
+    //   removed from |pending_dump_providers|.
+    DCHECK(!(*mdp_iter)->owned_dump_provider);
+    (*mdp_iter)->owned_dump_provider = std::move(owned_mdp);
+  } else if (subtle::NoBarrier_Load(&memory_tracing_enabled_)) {
+    // If you hit this DCHECK, your dump provider has a bug.
+    // Unregistration of a MemoryDumpProvider is safe only if:
+    // - The MDP has specified a sequenced task runner affinity AND the
+    //   unregistration happens on the same task runner. So that the MDP cannot
+    //   unregister and be in the middle of a OnMemoryDump() at the same time.
+    // - The MDP has NOT specified a task runner affinity and its ownership is
+    //   transferred via UnregisterAndDeleteDumpProviderSoon().
+    // In all the other cases, it is not possible to guarantee that the
+    // unregistration will not race with OnMemoryDump() calls.
+    DCHECK((*mdp_iter)->task_runner &&
+           (*mdp_iter)->task_runner->RunsTasksOnCurrentThread())
+        << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to "
+        << "unregister itself in a racy way. Please file a crbug.";
+  }
+
+  // The MDPInfo instance can still be referenced by the
+  // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason
+  // the MDPInfo is flagged as disabled. It will cause InvokeOnMemoryDump()
+  // to just skip it, without actually invoking the |mdp|, which might be
+  // destroyed by the caller soon after this method returns.
+  (*mdp_iter)->disabled = true;
+  dump_providers_.erase(mdp_iter);
+}
+
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    MemoryDumpLevelOfDetail level_of_detail,
+    const MemoryDumpCallback& callback) {
+  // Bail out immediately if tracing is not enabled at all or if the dump mode
+  // is not allowed.
+  if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)) ||
+      !IsDumpModeAllowed(level_of_detail)) {
+    VLOG(1) << kLogPrefix << " failed because " << kTraceCategory
+            << " tracing category is not enabled or the requested dump mode is "
+               "not allowed by trace config.";
+    if (!callback.is_null())
+      callback.Run(0u /* guid */, false /* success */);
+    return;
+  }
+
+  const uint64_t guid =
+      TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
+
+  // Creates an async event to keep track of the global dump evolution.
+  // The |wrapped_callback| will generate the ASYNC_END event and then invoke
+  // the real |callback| provided by the caller.
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "GlobalMemoryDump",
+                                    TRACE_ID_MANGLE(guid));
+  MemoryDumpCallback wrapped_callback = Bind(&OnGlobalDumpDone, callback);
+
+  // Technically there is no need to grab the |lock_| here as the delegate is
+  // long-lived and can only be set by Initialize(), which is locked and
+  // necessarily happens before memory_tracing_enabled_ == true.
+  // Not taking the |lock_|, though, is lakely make TSan barf and, at this point
+  // (memory-infra is enabled) we're not in the fast-path anymore.
+  MemoryDumpManagerDelegate* delegate;
+  {
+    AutoLock lock(lock_);
+    delegate = delegate_;
+  }
+
+  // The delegate will coordinate the IPC broadcast and at some point invoke
+  // CreateProcessDump() to get a dump for the current process.
+  MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail};
+  delegate->RequestGlobalMemoryDump(args, wrapped_callback);
+}
+
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    MemoryDumpLevelOfDetail level_of_detail) {
+  RequestGlobalDump(dump_type, level_of_detail, MemoryDumpCallback());
+}
+
+void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
+                                          const MemoryDumpCallback& callback) {
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump",
+                                    TRACE_ID_MANGLE(args.dump_guid));
+
+  // If argument filter is enabled then only background mode dumps should be
+  // allowed. In case the trace config passed for background tracing session
+  // missed the allowed modes argument, it crashes here instead of creating
+  // unexpected dumps.
+  if (TraceLog::GetInstance()
+          ->GetCurrentTraceConfig()
+          .IsArgumentFilterEnabled()) {
+    CHECK_EQ(MemoryDumpLevelOfDetail::BACKGROUND, args.level_of_detail);
+  }
+
+  std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
+  {
+    AutoLock lock(lock_);
+
+    // |dump_thread_| can be nullptr is tracing was disabled before reaching
+    // here. SetupNextMemoryDump() is robust enough to tolerate it and will
+    // NACK the dump.
+    pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
+        args, dump_providers_, session_state_, callback,
+        dump_thread_ ? dump_thread_->task_runner() : nullptr));
+
+    // Safety check to prevent reaching here without calling RequestGlobalDump,
+    // with disallowed modes. If |session_state_| is null then tracing is
+    // disabled.
+    CHECK(!session_state_ ||
+          session_state_->memory_dump_config().allowed_dump_modes.count(
+              args.level_of_detail));
+  }
+
+  TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump",
+                         TRACE_ID_MANGLE(args.dump_guid),
+                         TRACE_EVENT_FLAG_FLOW_OUT);
+
+  // Start the process dump. This involves task runner hops as specified by the
+  // MemoryDumpProvider(s) in RegisterDumpProvider()).
+  SetupNextMemoryDump(std::move(pmd_async_state));
+}
+
+// PostTask InvokeOnMemoryDump() to the dump provider's sequenced task runner. A
+// PostTask is always required for a generic SequencedTaskRunner to ensure that
+// no other task is running on it concurrently. SetupNextMemoryDump() and
+// InvokeOnMemoryDump() are called alternatively which linearizes the dump
+// provider's OnMemoryDump invocations.
+// At most one of either SetupNextMemoryDump() or InvokeOnMemoryDump() can be
+// active at any time for a given PMD, regardless of status of the |lock_|.
+// |lock_| is used in these functions purely to ensure consistency w.r.t.
+// (un)registrations of |dump_providers_|.
+void MemoryDumpManager::SetupNextMemoryDump(
+    std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+  HEAP_PROFILER_SCOPED_IGNORE;
+  // Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
+  // in the PostTask below don't end up registering their own dump providers
+  // (for discounting trace memory overhead) while holding the |lock_|.
+  TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+
+  // |dump_thread_| might be destroyed before getting this point.
+  // It means that tracing was disabled right before starting this dump.
+  // Anyway either tracing is stopped or this was the last hop, create a trace
+  // event, add it to the trace and finalize process dump invoking the callback.
+  if (!pmd_async_state->dump_thread_task_runner.get()) {
+    if (pmd_async_state->pending_dump_providers.empty()) {
+      VLOG(1) << kLogPrefix << " failed because dump thread was destroyed"
+              << " before finalizing the dump";
+    } else {
+      VLOG(1) << kLogPrefix << " failed because dump thread was destroyed"
+              << " before dumping "
+              << pmd_async_state->pending_dump_providers.back().get()->name;
+    }
+    pmd_async_state->dump_successful = false;
+    pmd_async_state->pending_dump_providers.clear();
+  }
+  if (pmd_async_state->pending_dump_providers.empty())
+    return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
+
+  // Read MemoryDumpProviderInfo thread safety considerations in
+  // memory_dump_manager.h when accessing |mdpinfo| fields.
+  MemoryDumpProviderInfo* mdpinfo =
+      pmd_async_state->pending_dump_providers.back().get();
+
+  // If we are in background tracing, we should invoke only the whitelisted
+  // providers. Ignore other providers and continue.
+  if (pmd_async_state->req_args.level_of_detail ==
+          MemoryDumpLevelOfDetail::BACKGROUND &&
+      !mdpinfo->whitelisted_for_background_mode) {
+    pmd_async_state->pending_dump_providers.pop_back();
+    return SetupNextMemoryDump(std::move(pmd_async_state));
+  }
+
+  // If the dump provider did not specify a task runner affinity, dump on
+  // |dump_thread_| which is already checked above for presence.
+  SequencedTaskRunner* task_runner = mdpinfo->task_runner.get();
+  if (!task_runner) {
+    DCHECK(mdpinfo->options.dumps_on_single_thread_task_runner);
+    task_runner = pmd_async_state->dump_thread_task_runner.get();
+    DCHECK(task_runner);
+  }
+
+  if (mdpinfo->options.dumps_on_single_thread_task_runner &&
+      task_runner->RunsTasksOnCurrentThread()) {
+    // If |dumps_on_single_thread_task_runner| is true then no PostTask is
+    // required if we are on the right thread.
+    return InvokeOnMemoryDump(pmd_async_state.release());
+  }
+
+  bool did_post_task = task_runner->PostTask(
+      FROM_HERE, Bind(&MemoryDumpManager::InvokeOnMemoryDump, Unretained(this),
+                      Unretained(pmd_async_state.get())));
+
+  if (did_post_task) {
+    // Ownership is tranferred to InvokeOnMemoryDump().
+    ignore_result(pmd_async_state.release());
+    return;
+  }
+
+  // PostTask usually fails only if the process or thread is shut down. So, the
+  // dump provider is disabled here. But, don't disable unbound dump providers.
+  // The utility thread is normally shutdown when disabling the trace and
+  // getting here in this case is expected.
+  if (mdpinfo->task_runner) {
+    LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
+               << "\". Failed to post task on the task runner provided.";
+
+    // A locked access is required to R/W |disabled| (for the
+    // UnregisterAndDeleteDumpProviderSoon() case).
+    AutoLock lock(lock_);
+    mdpinfo->disabled = true;
+  }
+
+  // PostTask failed. Ignore the dump provider and continue.
+  pmd_async_state->pending_dump_providers.pop_back();
+  SetupNextMemoryDump(std::move(pmd_async_state));
+}
+
+// This function is called on the right task runner for current MDP. It is
+// either the task runner specified by MDP or |dump_thread_task_runner| if the
+// MDP did not specify task runner. Invokes the dump provider's OnMemoryDump()
+// (unless disabled).
+void MemoryDumpManager::InvokeOnMemoryDump(
+    ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
+  HEAP_PROFILER_SCOPED_IGNORE;
+  // In theory |owned_pmd_async_state| should be a scoped_ptr. The only reason
+  // why it isn't is because of the corner case logic of |did_post_task|
+  // above, which needs to take back the ownership of the |pmd_async_state| when
+  // the PostTask() fails.
+  // Unfortunately, PostTask() destroys the scoped_ptr arguments upon failure
+  // to prevent accidental leaks. Using a scoped_ptr would prevent us to to
+  // skip the hop and move on. Hence the manual naked -> scoped ptr juggling.
+  auto pmd_async_state = WrapUnique(owned_pmd_async_state);
+  owned_pmd_async_state = nullptr;
+
+  // Read MemoryDumpProviderInfo thread safety considerations in
+  // memory_dump_manager.h when accessing |mdpinfo| fields.
+  MemoryDumpProviderInfo* mdpinfo =
+      pmd_async_state->pending_dump_providers.back().get();
+
+  DCHECK(!mdpinfo->task_runner ||
+         mdpinfo->task_runner->RunsTasksOnCurrentThread());
+
+  bool should_dump;
+  {
+    // A locked access is required to R/W |disabled| (for the
+    // UnregisterAndDeleteDumpProviderSoon() case).
+    AutoLock lock(lock_);
+
+    // Unregister the dump provider if it failed too many times consecutively.
+    if (!mdpinfo->disabled &&
+        mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
+      mdpinfo->disabled = true;
+      LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name
+                 << "\". Dump failed multiple times consecutively.";
+    }
+    should_dump = !mdpinfo->disabled;
+  }  // AutoLock lock(lock_);
+
+  if (should_dump) {
+    // Invoke the dump provider.
+    TRACE_EVENT_WITH_FLOW1(kTraceCategory,
+                           "MemoryDumpManager::InvokeOnMemoryDump",
+                           TRACE_ID_MANGLE(pmd_async_state->req_args.dump_guid),
+                           TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+                           "dump_provider.name", mdpinfo->name);
+
+    // Pid of the target process being dumped. Often kNullProcessId (= current
+    // process), non-zero when the coordinator process creates dumps on behalf
+    // of child processes (see crbug.com/461788).
+    ProcessId target_pid = mdpinfo->options.target_pid;
+    MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
+    ProcessMemoryDump* pmd =
+        pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid,
+                                                                  args);
+    bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd);
+    mdpinfo->consecutive_failures =
+        dump_successful ? 0 : mdpinfo->consecutive_failures + 1;
+  }
+
+  pmd_async_state->pending_dump_providers.pop_back();
+  SetupNextMemoryDump(std::move(pmd_async_state));
+}
+
+// static
+void MemoryDumpManager::FinalizeDumpAndAddToTrace(
+    std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+  HEAP_PROFILER_SCOPED_IGNORE;
+  DCHECK(pmd_async_state->pending_dump_providers.empty());
+  const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
+  if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) {
+    scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
+        pmd_async_state->callback_task_runner;
+    callback_task_runner->PostTask(
+        FROM_HERE, Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
+                        Passed(&pmd_async_state)));
+    return;
+  }
+
+  TRACE_EVENT_WITH_FLOW0(kTraceCategory,
+                         "MemoryDumpManager::FinalizeDumpAndAddToTrace",
+                         TRACE_ID_MANGLE(dump_guid), TRACE_EVENT_FLAG_FLOW_IN);
+
+  for (const auto& kv : pmd_async_state->process_dumps) {
+    ProcessId pid = kv.first;  // kNullProcessId for the current process.
+    ProcessMemoryDump* process_memory_dump = kv.second.get();
+    std::unique_ptr<TracedValue> traced_value(new TracedValue);
+    process_memory_dump->AsValueInto(traced_value.get());
+    traced_value->SetString("level_of_detail",
+                            MemoryDumpLevelOfDetailToString(
+                                pmd_async_state->req_args.level_of_detail));
+    const char* const event_name =
+        MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
+
+    std::unique_ptr<ConvertableToTraceFormat> event_value(
+        std::move(traced_value));
+    TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+        TRACE_EVENT_PHASE_MEMORY_DUMP,
+        TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+        trace_event_internal::kGlobalScope, dump_guid, pid,
+        kTraceEventNumArgs, kTraceEventArgNames,
+        kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+        TRACE_EVENT_FLAG_HAS_ID);
+  }
+
+  bool tracing_still_enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &tracing_still_enabled);
+  if (!tracing_still_enabled) {
+    pmd_async_state->dump_successful = false;
+    VLOG(1) << kLogPrefix << " failed because tracing was disabled before"
+            << " the dump was completed";
+  }
+
+  if (!pmd_async_state->callback.is_null()) {
+    pmd_async_state->callback.Run(dump_guid, pmd_async_state->dump_successful);
+    pmd_async_state->callback.Reset();
+  }
+
+  TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
+                                  TRACE_ID_MANGLE(dump_guid));
+}
+
+void MemoryDumpManager::OnTraceLogEnabled() {
+  bool enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+  if (!enabled)
+    return;
+
+  // Initialize the TraceLog for the current thread. This is to avoid that the
+  // TraceLog memory dump provider is registered lazily in the PostTask() below
+  // while the |lock_| is taken;
+  TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+
+  // Spin-up the thread used to invoke unbound dump providers.
+  std::unique_ptr<Thread> dump_thread(new Thread("MemoryInfra"));
+  if (!dump_thread->Start()) {
+    LOG(ERROR) << "Failed to start the memory-infra thread for tracing";
+    return;
+  }
+
+  const TraceConfig trace_config =
+      TraceLog::GetInstance()->GetCurrentTraceConfig();
+  scoped_refptr<MemoryDumpSessionState> session_state =
+      new MemoryDumpSessionState;
+  session_state->SetMemoryDumpConfig(trace_config.memory_dump_config());
+  if (heap_profiling_enabled_) {
+    // If heap profiling is enabled, the stack frame deduplicator and type name
+    // deduplicator will be in use. Add a metadata events to write the frames
+    // and type IDs.
+    session_state->SetStackFrameDeduplicator(
+        WrapUnique(new StackFrameDeduplicator));
+
+    session_state->SetTypeNameDeduplicator(
+        WrapUnique(new TypeNameDeduplicator));
+
+    TRACE_EVENT_API_ADD_METADATA_EVENT(
+        TraceLog::GetCategoryGroupEnabled("__metadata"), "stackFrames",
+        "stackFrames",
+        WrapUnique(new SessionStateConvertableProxy<StackFrameDeduplicator>(
+            session_state, &MemoryDumpSessionState::stack_frame_deduplicator)));
+
+    TRACE_EVENT_API_ADD_METADATA_EVENT(
+        TraceLog::GetCategoryGroupEnabled("__metadata"), "typeNames",
+        "typeNames",
+        WrapUnique(new SessionStateConvertableProxy<TypeNameDeduplicator>(
+            session_state, &MemoryDumpSessionState::type_name_deduplicator)));
+  }
+
+  {
+    AutoLock lock(lock_);
+
+    DCHECK(delegate_);  // At this point we must have a delegate.
+    session_state_ = session_state;
+
+    DCHECK(!dump_thread_);
+    dump_thread_ = std::move(dump_thread);
+
+    subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
+
+    // TODO(primiano): This is a temporary hack to disable periodic memory dumps
+    // when running memory benchmarks until telemetry uses TraceConfig to
+    // enable/disable periodic dumps. See crbug.com/529184 .
+    if (!is_coordinator_ ||
+        CommandLine::ForCurrentProcess()->HasSwitch(
+            "enable-memory-benchmarking")) {
+      return;
+    }
+  }
+
+  // Enable periodic dumps if necessary.
+  periodic_dump_timer_.Start(trace_config.memory_dump_config().triggers);
+}
+
+void MemoryDumpManager::OnTraceLogDisabled() {
+  // There might be a memory dump in progress while this happens. Therefore,
+  // ensure that the MDM state which depends on the tracing enabled / disabled
+  // state is always accessed by the dumping methods holding the |lock_|.
+  subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
+  std::unique_ptr<Thread> dump_thread;
+  {
+    AutoLock lock(lock_);
+    dump_thread = std::move(dump_thread_);
+    session_state_ = nullptr;
+  }
+
+  // Thread stops are blocking and must be performed outside of the |lock_|
+  // or will deadlock (e.g., if SetupNextMemoryDump() tries to acquire it).
+  periodic_dump_timer_.Stop();
+  if (dump_thread)
+    dump_thread->Stop();
+}
+
+bool MemoryDumpManager::IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode) {
+  AutoLock lock(lock_);
+  if (!session_state_)
+    return false;
+  return session_state_->memory_dump_config().allowed_dump_modes.count(
+             dump_mode) != 0;
+}
+
+uint64_t MemoryDumpManager::GetTracingProcessId() const {
+  return delegate_->GetTracingProcessId();
+}
+
+MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
+    MemoryDumpProvider* dump_provider,
+    const char* name,
+    scoped_refptr<SequencedTaskRunner> task_runner,
+    const MemoryDumpProvider::Options& options,
+    bool whitelisted_for_background_mode)
+    : dump_provider(dump_provider),
+      name(name),
+      task_runner(std::move(task_runner)),
+      options(options),
+      consecutive_failures(0),
+      disabled(false),
+      whitelisted_for_background_mode(whitelisted_for_background_mode) {}
+
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {}
+
+bool MemoryDumpManager::MemoryDumpProviderInfo::Comparator::operator()(
+    const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& a,
+    const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& b) const {
+  if (!a || !b)
+    return a.get() < b.get();
+  // Ensure that unbound providers (task_runner == nullptr) always run last.
+  // Rationale: some unbound dump providers are known to be slow, keep them last
+  // to avoid skewing timings of the other dump providers.
+  return std::tie(a->task_runner, a->dump_provider) >
+         std::tie(b->task_runner, b->dump_provider);
+}
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
+    MemoryDumpRequestArgs req_args,
+    const MemoryDumpProviderInfo::OrderedSet& dump_providers,
+    scoped_refptr<MemoryDumpSessionState> session_state,
+    MemoryDumpCallback callback,
+    scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner)
+    : req_args(req_args),
+      session_state(std::move(session_state)),
+      callback(callback),
+      dump_successful(true),
+      callback_task_runner(ThreadTaskRunnerHandle::Get()),
+      dump_thread_task_runner(std::move(dump_thread_task_runner)) {
+  pending_dump_providers.reserve(dump_providers.size());
+  pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
+}
+
+MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
+}
+
+ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
+    GetOrCreateMemoryDumpContainerForProcess(ProcessId pid,
+                                             const MemoryDumpArgs& dump_args) {
+  auto iter = process_dumps.find(pid);
+  if (iter == process_dumps.end()) {
+    std::unique_ptr<ProcessMemoryDump> new_pmd(
+        new ProcessMemoryDump(session_state, dump_args));
+    iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first;
+  }
+  return iter->second.get();
+}
+
+MemoryDumpManager::PeriodicGlobalDumpTimer::PeriodicGlobalDumpTimer() {}
+
+MemoryDumpManager::PeriodicGlobalDumpTimer::~PeriodicGlobalDumpTimer() {
+  Stop();
+}
+
+void MemoryDumpManager::PeriodicGlobalDumpTimer::Start(
+    const std::vector<TraceConfig::MemoryDumpConfig::Trigger>& triggers_list) {
+  if (triggers_list.empty())
+    return;
+
+  // At the moment the periodic support is limited to at most one periodic
+  // trigger per dump mode. All intervals should be an integer multiple of the
+  // smallest interval specified.
+  periodic_dumps_count_ = 0;
+  uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
+  uint32_t light_dump_period_ms = 0;
+  uint32_t heavy_dump_period_ms = 0;
+  DCHECK_LE(triggers_list.size(), 3u);
+  auto* mdm = MemoryDumpManager::GetInstance();
+  for (const TraceConfig::MemoryDumpConfig::Trigger& config : triggers_list) {
+    DCHECK_NE(0u, config.periodic_interval_ms);
+    switch (config.level_of_detail) {
+      case MemoryDumpLevelOfDetail::BACKGROUND:
+        DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::BACKGROUND));
+        break;
+      case MemoryDumpLevelOfDetail::LIGHT:
+        DCHECK_EQ(0u, light_dump_period_ms);
+        DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::LIGHT));
+        light_dump_period_ms = config.periodic_interval_ms;
+        break;
+      case MemoryDumpLevelOfDetail::DETAILED:
+        DCHECK_EQ(0u, heavy_dump_period_ms);
+        DCHECK(mdm->IsDumpModeAllowed(MemoryDumpLevelOfDetail::DETAILED));
+        heavy_dump_period_ms = config.periodic_interval_ms;
+        break;
+    }
+    min_timer_period_ms =
+        std::min(min_timer_period_ms, config.periodic_interval_ms);
+  }
+
+  DCHECK_EQ(0u, light_dump_period_ms % min_timer_period_ms);
+  light_dump_rate_ = light_dump_period_ms / min_timer_period_ms;
+  DCHECK_EQ(0u, heavy_dump_period_ms % min_timer_period_ms);
+  heavy_dump_rate_ = heavy_dump_period_ms / min_timer_period_ms;
+
+  timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(min_timer_period_ms),
+               base::Bind(&PeriodicGlobalDumpTimer::RequestPeriodicGlobalDump,
+                          base::Unretained(this)));
+}
+
+void MemoryDumpManager::PeriodicGlobalDumpTimer::Stop() {
+  if (IsRunning()) {
+    timer_.Stop();
+  }
+}
+
+bool MemoryDumpManager::PeriodicGlobalDumpTimer::IsRunning() {
+  return timer_.IsRunning();
+}
+
+void MemoryDumpManager::PeriodicGlobalDumpTimer::RequestPeriodicGlobalDump() {
+  MemoryDumpLevelOfDetail level_of_detail = MemoryDumpLevelOfDetail::BACKGROUND;
+  if (light_dump_rate_ > 0 && periodic_dumps_count_ % light_dump_rate_ == 0)
+    level_of_detail = MemoryDumpLevelOfDetail::LIGHT;
+  if (heavy_dump_rate_ > 0 && periodic_dumps_count_ % heavy_dump_rate_ == 0)
+    level_of_detail = MemoryDumpLevelOfDetail::DETAILED;
+  ++periodic_dumps_count_;
+
+  MemoryDumpManager::GetInstance()->RequestGlobalDump(
+      MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/memory_dump_manager.h b/libchrome/base/trace_event/memory_dump_manager.h
new file mode 100644
index 0000000..06b772c
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_manager.h
@@ -0,0 +1,410 @@
+// 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 <stdint.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.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/process_memory_dump.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+class Thread;
+
+namespace trace_event {
+
+class MemoryDumpManagerDelegate;
+class MemoryDumpProvider;
+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 kTraceCategory;
+  static const char* const kLogPrefix;
+
+  // This value is returned as the tracing id of the child processes by
+  // GetTracingProcessId() when tracing is not enabled.
+  static const uint64_t kInvalidTracingProcessId;
+
+  static MemoryDumpManager* GetInstance();
+
+  // Invoked once per process to listen to trace begin / end events.
+  // Initialization can happen after (Un)RegisterMemoryDumpProvider() calls
+  // and the MemoryDumpManager guarantees to support this.
+  // On the other side, the MemoryDumpManager will not be fully operational
+  // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
+  // Arguments:
+  //  is_coordinator: if true this MemoryDumpManager instance will act as a
+  //      coordinator and schedule periodic dumps (if enabled via TraceConfig);
+  //      false when the MemoryDumpManager is initialized in a slave process.
+  //  delegate: inversion-of-control interface for embedder-specific behaviors
+  //      (multiprocess handshaking). See the lifetime and thread-safety
+  //      requirements in the |MemoryDumpManagerDelegate| docstring.
+  void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator);
+
+  // (Un)Registers a MemoryDumpProvider instance.
+  // Args:
+  //  - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
+  //      does NOT take memory ownership of |mdp|, which is expected to either
+  //      be a singleton or unregister itself.
+  //  - name: a friendly name (duplicates allowed). Used for debugging and
+  //      run-time profiling of memory-infra internals. Must be a long-lived
+  //      C string.
+  //  - task_runner: either a SingleThreadTaskRunner or SequencedTaskRunner. All
+  //      the calls to |mdp| will be run on the given |task_runner|. If passed
+  //      null |mdp| should be able to handle calls on arbitrary threads.
+  //  - options: extra optional arguments. See memory_dump_provider.h.
+  void RegisterDumpProvider(MemoryDumpProvider* mdp,
+                            const char* name,
+                            scoped_refptr<SingleThreadTaskRunner> task_runner);
+  void RegisterDumpProvider(MemoryDumpProvider* mdp,
+                            const char* name,
+                            scoped_refptr<SingleThreadTaskRunner> task_runner,
+                            MemoryDumpProvider::Options options);
+  void RegisterDumpProviderWithSequencedTaskRunner(
+      MemoryDumpProvider* mdp,
+      const char* name,
+      scoped_refptr<SequencedTaskRunner> task_runner,
+      MemoryDumpProvider::Options options);
+  void UnregisterDumpProvider(MemoryDumpProvider* mdp);
+
+  // Unregisters an unbound dump provider and takes care about its deletion
+  // asynchronously. Can be used only for for dump providers with no
+  // task-runner affinity.
+  // This method takes ownership of the dump provider and guarantees that:
+  //  - The |mdp| will be deleted at some point in the near future.
+  //  - Its deletion will not happen concurrently with the OnMemoryDump() call.
+  // Note that OnMemoryDump() calls can still happen after this method returns.
+  void UnregisterAndDeleteDumpProviderSoon(
+      std::unique_ptr<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,
+                         MemoryDumpLevelOfDetail level_of_detail,
+                         const MemoryDumpCallback& callback);
+
+  // Same as above (still asynchronous), but without callback.
+  void RequestGlobalDump(MemoryDumpType dump_type,
+                         MemoryDumpLevelOfDetail level_of_detail);
+
+  // TraceLog::EnabledStateObserver implementation.
+  void OnTraceLogEnabled() override;
+  void OnTraceLogDisabled() override;
+
+  // Returns true if the dump mode is allowed for current tracing session.
+  bool IsDumpModeAllowed(MemoryDumpLevelOfDetail dump_mode);
+
+  // 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_for_testing()
+      const {
+    return session_state_;
+  }
+
+  // Returns a unique id for identifying the processes. The id can be
+  // retrieved by child processes only when tracing is enabled. This is
+  // intended to express cross-process sharing of memory dumps on the
+  // child-process side, without having to know its own child process id.
+  uint64_t GetTracingProcessId() const;
+
+  // Returns the name for a the allocated_objects dump. Use this to declare
+  // suballocator dumps from other dump providers.
+  // It will return nullptr if there is no dump provider for the system
+  // allocator registered (which is currently the case for Mac OS).
+  const char* system_allocator_pool_name() const {
+    return kSystemAllocatorPoolName;
+  };
+
+  // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
+  void set_dumper_registrations_ignored_for_testing(bool ignored) {
+    dumper_registrations_ignored_for_testing_ = ignored;
+  }
+
+ private:
+  friend std::default_delete<MemoryDumpManager>;  // For the testing instance.
+  friend struct DefaultSingletonTraits<MemoryDumpManager>;
+  friend class MemoryDumpManagerDelegate;
+  friend class MemoryDumpManagerTest;
+
+  // Descriptor used to hold information about registered MDPs.
+  // Some important considerations about lifetime of this object:
+  // - In nominal conditions, all the MemoryDumpProviderInfo instances live in
+  //   the |dump_providers_| collection (% unregistration while dumping).
+  // - Upon each dump they (actually their scoped_refptr-s) are copied into
+  //   the ProcessMemoryDumpAsyncState. This is to allow removal (see below).
+  // - When the MDP.OnMemoryDump() is invoked, the corresponding MDPInfo copy
+  //   inside ProcessMemoryDumpAsyncState is removed.
+  // - In most cases, the MDPInfo is destroyed within UnregisterDumpProvider().
+  // - If UnregisterDumpProvider() is called while a dump is in progress, the
+  //   MDPInfo is destroyed in SetupNextMemoryDump() or InvokeOnMemoryDump(),
+  //   when the copy inside ProcessMemoryDumpAsyncState is erase()-d.
+  // - The non-const fields of MemoryDumpProviderInfo are safe to access only
+  //   on tasks running in the |task_runner|, unless the thread has been
+  //   destroyed.
+  struct MemoryDumpProviderInfo
+      : public RefCountedThreadSafe<MemoryDumpProviderInfo> {
+    // Define a total order based on the |task_runner| affinity, so that MDPs
+    // belonging to the same SequencedTaskRunner are adjacent in the set.
+    struct Comparator {
+      bool operator()(const scoped_refptr<MemoryDumpProviderInfo>& a,
+                      const scoped_refptr<MemoryDumpProviderInfo>& b) const;
+    };
+    using OrderedSet =
+        std::set<scoped_refptr<MemoryDumpProviderInfo>, Comparator>;
+
+    MemoryDumpProviderInfo(MemoryDumpProvider* dump_provider,
+                           const char* name,
+                           scoped_refptr<SequencedTaskRunner> task_runner,
+                           const MemoryDumpProvider::Options& options,
+                           bool whitelisted_for_background_mode);
+
+    MemoryDumpProvider* const dump_provider;
+
+    // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon().
+    // nullptr in all other cases.
+    std::unique_ptr<MemoryDumpProvider> owned_dump_provider;
+
+    // Human readable name, for debugging and testing. Not necessarily unique.
+    const char* const name;
+
+    // The task runner affinity. Can be nullptr, in which case the dump provider
+    // will be invoked on |dump_thread_|.
+    const scoped_refptr<SequencedTaskRunner> task_runner;
+
+    // The |options| arg passed to RegisterDumpProvider().
+    const MemoryDumpProvider::Options options;
+
+    // For fail-safe logic (auto-disable failing MDPs).
+    int consecutive_failures;
+
+    // Flagged either by the auto-disable logic or during unregistration.
+    bool disabled;
+
+    // True if the dump provider is whitelisted for background mode.
+    const bool whitelisted_for_background_mode;
+
+   private:
+    friend class base::RefCountedThreadSafe<MemoryDumpProviderInfo>;
+    ~MemoryDumpProviderInfo();
+
+    DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderInfo);
+  };
+
+  // Holds the state of a process memory dump that needs to be carried over
+  // across task runners in order to fulfil an asynchronous CreateProcessDump()
+  // request. At any time exactly one task runner owns a
+  // ProcessMemoryDumpAsyncState.
+  struct ProcessMemoryDumpAsyncState {
+    ProcessMemoryDumpAsyncState(
+        MemoryDumpRequestArgs req_args,
+        const MemoryDumpProviderInfo::OrderedSet& dump_providers,
+        scoped_refptr<MemoryDumpSessionState> session_state,
+        MemoryDumpCallback callback,
+        scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner);
+    ~ProcessMemoryDumpAsyncState();
+
+    // Gets or creates the memory dump container for the given target process.
+    ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(
+        ProcessId pid,
+        const MemoryDumpArgs& dump_args);
+
+    // A map of ProcessId -> ProcessMemoryDump, one for each target process
+    // being dumped from the current process. Typically each process dumps only
+    // for itself, unless dump providers specify a different |target_process| in
+    // MemoryDumpProvider::Options.
+    std::map<ProcessId, std::unique_ptr<ProcessMemoryDump>> process_dumps;
+
+    // The arguments passed to the initial CreateProcessDump() request.
+    const MemoryDumpRequestArgs req_args;
+
+    // An ordered sequence of dump providers that have to be invoked to complete
+    // the dump. This is a copy of |dump_providers_| at the beginning of a dump
+    // and becomes empty at the end, when all dump providers have been invoked.
+    std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers;
+
+    // The trace-global session state.
+    scoped_refptr<MemoryDumpSessionState> session_state;
+
+    // Callback passed to the initial call to CreateProcessDump().
+    MemoryDumpCallback callback;
+
+    // The |success| field that will be passed as argument to the |callback|.
+    bool dump_successful;
+
+    // The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
+    // should be invoked. This is the thread on which the initial
+    // CreateProcessDump() request was called.
+    const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
+
+    // The thread on which unbound dump providers should be invoked.
+    // This is essentially |dump_thread_|.task_runner() but needs to be kept
+    // as a separate variable as it needs to be accessed by arbitrary dumpers'
+    // threads outside of the lock_ to avoid races when disabling tracing.
+    // It is immutable for all the duration of a tracing session.
+    const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
+  };
+
+  // Sets up periodic memory dump timers to start global dump requests based on
+  // the dump triggers from trace config.
+  class BASE_EXPORT PeriodicGlobalDumpTimer {
+   public:
+    PeriodicGlobalDumpTimer();
+    ~PeriodicGlobalDumpTimer();
+
+    void Start(const std::vector<TraceConfig::MemoryDumpConfig::Trigger>&
+                   triggers_list);
+    void Stop();
+
+    bool IsRunning();
+
+   private:
+    // Periodically called by the timer.
+    void RequestPeriodicGlobalDump();
+
+    RepeatingTimer timer_;
+    uint32_t periodic_dumps_count_;
+    uint32_t light_dump_rate_;
+    uint32_t heavy_dump_rate_;
+
+    DISALLOW_COPY_AND_ASSIGN(PeriodicGlobalDumpTimer);
+  };
+
+  static const int kMaxConsecutiveFailuresCount;
+  static const char* const kSystemAllocatorPoolName;
+
+  MemoryDumpManager();
+  ~MemoryDumpManager() override;
+
+  static void SetInstanceForTesting(MemoryDumpManager* instance);
+  static void FinalizeDumpAndAddToTrace(
+      std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
+
+  // Enable heap profiling if kEnableHeapProfiling is specified.
+  void EnableHeapProfilingIfNeeded();
+
+  // 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);
+
+  // Calls InvokeOnMemoryDump() for the next MDP on the task runner specified by
+  // the MDP while registration. On failure to do so, skips and continues to
+  // next MDP.
+  void SetupNextMemoryDump(
+      std::unique_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
+
+  // Invokes OnMemoryDump() of the next MDP and calls SetupNextMemoryDump() at
+  // the end to continue the ProcessMemoryDump. Should be called on the MDP task
+  // runner.
+  void InvokeOnMemoryDump(ProcessMemoryDumpAsyncState* owned_pmd_async_state);
+
+  // Helper for RegierDumpProvider* functions.
+  void RegisterDumpProviderInternal(
+      MemoryDumpProvider* mdp,
+      const char* name,
+      scoped_refptr<SequencedTaskRunner> task_runner,
+      const MemoryDumpProvider::Options& options);
+
+  // Helper for the public UnregisterDumpProvider* functions.
+  void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp,
+                                      bool take_mdp_ownership_and_delete_async);
+
+  // An ordererd set of registered MemoryDumpProviderInfo(s), sorted by task
+  // runner affinity (MDPs belonging to the same task runners are adjacent).
+  MemoryDumpProviderInfo::OrderedSet dump_providers_;
+
+  // Shared among all the PMDs to keep state scoped to the tracing session.
+  scoped_refptr<MemoryDumpSessionState> session_state_;
+
+  MemoryDumpManagerDelegate* delegate_;  // Not owned.
+
+  // When true, this instance is in charge of coordinating periodic dumps.
+  bool is_coordinator_;
+
+  // 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.
+  PeriodicGlobalDumpTimer periodic_dump_timer_;
+
+  // Thread used for MemoryDumpProviders which don't specify a task runner
+  // affinity.
+  std::unique_ptr<Thread> dump_thread_;
+
+  // The unique id of the child process. This is created only for tracing and is
+  // expected to be valid only when tracing is enabled.
+  uint64_t tracing_process_id_;
+
+  // When true, calling |RegisterMemoryDumpProvider| is a no-op.
+  bool dumper_registrations_ignored_for_testing_;
+
+  // Whether new memory dump providers should be told to enable heap profiling.
+  bool heap_profiling_enabled_;
+
+  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;
+
+  // Returns tracing process id of the current process. This is used by
+  // MemoryDumpManager::GetTracingProcessId.
+  virtual uint64_t GetTracingProcessId() 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/libchrome/base/trace_event/memory_dump_manager_unittest.cc b/libchrome/base/trace_event/memory_dump_manager_unittest.cc
new file mode 100644
index 0000000..d14093c
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_manager_unittest.cc
@@ -0,0 +1,1171 @@
+// 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 <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_io_thread.h"
+#include "base/test/trace_event_analyzer.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_infra_background_whitelist.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_config_memory_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::AnyNumber;
+using testing::AtMost;
+using testing::Between;
+using testing::Invoke;
+using testing::Return;
+
+namespace base {
+namespace trace_event {
+
+// GTest matchers for MemoryDumpRequestArgs arguments.
+MATCHER(IsDetailedDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::DETAILED;
+}
+
+MATCHER(IsLightDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
+}
+
+MATCHER(IsBackgroundDump, "") {
+  return arg.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND;
+}
+
+namespace {
+
+const char* kMDPName = "TestDumpProvider";
+const char* kWhitelistedMDPName = "WhitelistedTestDumpProvider";
+const char* const kTestMDPWhitelist[] = {kWhitelistedMDPName, nullptr};
+
+void RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    const MemoryDumpProvider::Options& options,
+    const char* name = kMDPName) {
+  MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
+  mdm->set_dumper_registrations_ignored_for_testing(false);
+  mdm->RegisterDumpProvider(mdp, name, std::move(task_runner), options);
+  mdm->set_dumper_registrations_ignored_for_testing(true);
+}
+
+void RegisterDumpProvider(MemoryDumpProvider* mdp) {
+  RegisterDumpProvider(mdp, nullptr, MemoryDumpProvider::Options());
+}
+
+void RegisterDumpProviderWithSequencedTaskRunner(
+    MemoryDumpProvider* mdp,
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    const MemoryDumpProvider::Options& options) {
+  MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
+  mdm->set_dumper_registrations_ignored_for_testing(false);
+  mdm->RegisterDumpProviderWithSequencedTaskRunner(mdp, kMDPName, task_runner,
+                                                   options);
+  mdm->set_dumper_registrations_ignored_for_testing(true);
+}
+
+void OnTraceDataCollected(Closure quit_closure,
+                          trace_event::TraceResultBuffer* buffer,
+                          const scoped_refptr<RefCountedString>& json,
+                          bool has_more_events) {
+  buffer->AddFragment(json->data());
+  if (!has_more_events)
+    quit_closure.Run();
+}
+
+}  // namespace
+
+// Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
+// requests locally to the MemoryDumpManager instead of performing IPC dances.
+class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
+ public:
+  MemoryDumpManagerDelegateForTesting() {
+    ON_CALL(*this, RequestGlobalMemoryDump(_, _))
+        .WillByDefault(Invoke(
+            this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump));
+  }
+
+  MOCK_METHOD2(RequestGlobalMemoryDump,
+               void(const MemoryDumpRequestArgs& args,
+                    const MemoryDumpCallback& callback));
+
+  uint64_t GetTracingProcessId() const override {
+    NOTREACHED();
+    return MemoryDumpManager::kInvalidTracingProcessId;
+  }
+
+  // Promote the CreateProcessDump to public so it can be used by test fixtures.
+  using MemoryDumpManagerDelegate::CreateProcessDump;
+};
+
+class MockMemoryDumpProvider : public MemoryDumpProvider {
+ public:
+  MOCK_METHOD0(Destructor, void());
+  MOCK_METHOD2(OnMemoryDump,
+               bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
+
+  MockMemoryDumpProvider() : enable_mock_destructor(false) {
+    ON_CALL(*this, OnMemoryDump(_, _))
+        .WillByDefault(Invoke([](const MemoryDumpArgs&,
+                                 ProcessMemoryDump* pmd) -> bool {
+          // |session_state| should not be null under any circumstances when
+          // invoking a memory dump. The problem might arise in race conditions
+          // like crbug.com/600570 .
+          EXPECT_TRUE(pmd->session_state().get() != nullptr);
+          return true;
+        }));
+  }
+  ~MockMemoryDumpProvider() override {
+    if (enable_mock_destructor)
+      Destructor();
+  }
+
+  bool enable_mock_destructor;
+};
+
+class TestSequencedTaskRunner : public SequencedTaskRunner {
+ public:
+  TestSequencedTaskRunner()
+      : worker_pool_(
+            new SequencedWorkerPool(2 /* max_threads */, "Test Task Runner")),
+        enabled_(true),
+        num_of_post_tasks_(0) {}
+
+  void set_enabled(bool value) { enabled_ = value; }
+  unsigned no_of_post_tasks() const { return num_of_post_tasks_; }
+
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override {
+    NOTREACHED();
+    return false;
+  }
+
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override {
+    num_of_post_tasks_++;
+    if (enabled_)
+      return worker_pool_->PostSequencedWorkerTask(token_, from_here, task);
+    return false;
+  }
+
+  bool RunsTasksOnCurrentThread() const override {
+    return worker_pool_->IsRunningSequenceOnCurrentThread(token_);
+  }
+
+ private:
+  ~TestSequencedTaskRunner() override {}
+
+  scoped_refptr<SequencedWorkerPool> worker_pool_;
+  const SequencedWorkerPool::SequenceToken token_;
+  bool enabled_;
+  unsigned num_of_post_tasks_;
+};
+
+class MemoryDumpManagerTest : public testing::Test {
+ public:
+  MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {}
+
+  void SetUp() override {
+    last_callback_success_ = false;
+    message_loop_.reset(new MessageLoop());
+    mdm_.reset(new MemoryDumpManager());
+    MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+    ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance());
+    delegate_.reset(new MemoryDumpManagerDelegateForTesting);
+  }
+
+  void TearDown() override {
+    MemoryDumpManager::SetInstanceForTesting(nullptr);
+    mdm_.reset();
+    delegate_.reset();
+    message_loop_.reset();
+    TraceLog::DeleteForTesting();
+  }
+
+  // Turns a Closure into a MemoryDumpCallback, keeping track of the callback
+  // result and taking care of posting the closure on the correct task runner.
+  void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
+                           Closure closure,
+                           uint64_t dump_guid,
+                           bool success) {
+    last_callback_success_ = success;
+    task_runner->PostTask(FROM_HERE, closure);
+  }
+
+ protected:
+  void InitializeMemoryDumpManager(bool is_coordinator) {
+    mdm_->set_dumper_registrations_ignored_for_testing(true);
+    mdm_->Initialize(delegate_.get(), is_coordinator);
+  }
+
+  void RequestGlobalDumpAndWait(MemoryDumpType dump_type,
+                                MemoryDumpLevelOfDetail level_of_detail) {
+    RunLoop run_loop;
+    MemoryDumpCallback callback =
+        Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+             ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure());
+    mdm_->RequestGlobalDump(dump_type, level_of_detail, callback);
+    run_loop.Run();
+  }
+
+  void EnableTracingWithLegacyCategories(const char* category) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
+                                        TraceLog::RECORDING_MODE);
+  }
+
+  void EnableTracingWithTraceConfig(const std::string& trace_config) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config),
+                                        TraceLog::RECORDING_MODE);
+  }
+
+  void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
+
+  bool IsPeriodicDumpingEnabled() const {
+    return mdm_->periodic_dump_timer_.IsRunning();
+  }
+
+  int GetMaxConsecutiveFailuresCount() const {
+    return MemoryDumpManager::kMaxConsecutiveFailuresCount;
+  }
+
+  const MemoryDumpProvider::Options kDefaultOptions;
+  std::unique_ptr<MemoryDumpManager> mdm_;
+  std::unique_ptr<MemoryDumpManagerDelegateForTesting> delegate_;
+  bool last_callback_success_;
+
+ private:
+  std::unique_ptr<MessageLoop> message_loop_;
+
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+};
+
+// Basic sanity checks. Registers a memory dump provider and checks that it is
+// called, but only when memory-infra is enabled.
+TEST_F(MemoryDumpManagerTest, SingleDumper) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp);
+
+  // Check that the dumper is not called if the memory category is not enabled.
+  EnableTracingWithLegacyCategories("foobar-but-not-memory");
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+
+  // Now repeat enabling the memory category and check that the dumper is
+  // invoked this time.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
+  for (int i = 0; i < 3; ++i)
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  // Finally check the unregister logic: the delegate will be invoked but not
+  // the dump provider, as it has been unregistered.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
+  EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+
+  for (int i = 0; i < 3; ++i) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+  DisableTracing();
+}
+
+// Checks that requesting dumps with high level of detail actually propagates
+// the level of the detail properly to OnMemoryDump() call on dump providers.
+TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
+
+  RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  // Check that requesting dumps with low level of detail actually propagates to
+  // OnMemoryDump() call on dump providers.
+  RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::LIGHT);
+  DisableTracing();
+  mdm_->UnregisterDumpProvider(&mdp);
+}
+
+// Checks that the SharedSessionState object is acqually shared over time.
+TEST_F(MemoryDumpManagerTest, SharedSessionState) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+  RegisterDumpProvider(&mdp1);
+  RegisterDumpProvider(&mdp2);
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  const MemoryDumpSessionState* session_state =
+      mdm_->session_state_for_testing().get();
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+      .Times(2)
+      .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+                                             ProcessMemoryDump* pmd) -> bool {
+        EXPECT_EQ(session_state, pmd->session_state().get());
+        return true;
+      }));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+      .Times(2)
+      .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&,
+                                             ProcessMemoryDump* pmd) -> bool {
+        EXPECT_EQ(session_state, pmd->session_state().get());
+        return true;
+      }));
+
+  for (int i = 0; i < 2; ++i) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+
+  DisableTracing();
+}
+
+// Checks that the (Un)RegisterDumpProvider logic behaves sanely.
+TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+
+  // Enable only mdp1.
+  RegisterDumpProvider(&mdp1);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+
+  // Invert: enable mdp1 and disable mdp2.
+  mdm_->UnregisterDumpProvider(&mdp1);
+  RegisterDumpProvider(&mdp2);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+
+  // Enable both mdp1 and mdp2.
+  RegisterDumpProvider(&mdp1);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+}
+
+// Checks that the dump provider invocations depend only on the current
+// registration state and not on previous registrations and dumps.
+TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp;
+
+  RegisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+
+  RegisterDumpProvider(&mdp);
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+
+  RegisterDumpProvider(&mdp);
+  mdm_->UnregisterDumpProvider(&mdp);
+  RegisterDumpProvider(&mdp);
+
+  {
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
+    EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    DisableTracing();
+  }
+}
+
+// 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, RespectTaskRunnerAffinity) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  const uint32_t kNumInitialThreads = 8;
+
+  std::vector<std::unique_ptr<Thread>> threads;
+  std::vector<std::unique_ptr<MockMemoryDumpProvider>> 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_t i = kNumInitialThreads; i > 0; --i) {
+    threads.push_back(WrapUnique(new Thread("test thread")));
+    auto* thread = threads.back().get();
+    thread->Start();
+    scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
+    mdps.push_back(WrapUnique(new MockMemoryDumpProvider()));
+    auto* mdp = mdps.back().get();
+    RegisterDumpProvider(mdp, task_runner, kDefaultOptions);
+    EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+        .Times(i)
+        .WillRepeatedly(Invoke(
+            [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+              EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+              return true;
+            }));
+  }
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  while (!threads.empty()) {
+    last_callback_success_ = false;
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    EXPECT_TRUE(last_callback_success_);
+
+    // 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().get()));
+      threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
+                                                      run_loop.QuitClosure());
+      run_loop.Run();
+    }
+    mdps.pop_back();
+    threads.back()->Stop();
+    threads.pop_back();
+  }
+
+  DisableTracing();
+}
+
+// Check that the memory dump calls are always posted on task runner for
+// SequencedTaskRunner case and that the dump provider gets disabled when
+// PostTask fails, but the dump still succeeds.
+TEST_F(MemoryDumpManagerTest, PostTaskForSequencedTaskRunner) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  std::vector<MockMemoryDumpProvider> mdps(3);
+  scoped_refptr<TestSequencedTaskRunner> task_runner1(
+      make_scoped_refptr(new TestSequencedTaskRunner()));
+  scoped_refptr<TestSequencedTaskRunner> task_runner2(
+      make_scoped_refptr(new TestSequencedTaskRunner()));
+  RegisterDumpProviderWithSequencedTaskRunner(&mdps[0], task_runner1,
+                                              kDefaultOptions);
+  RegisterDumpProviderWithSequencedTaskRunner(&mdps[1], task_runner2,
+                                              kDefaultOptions);
+  RegisterDumpProviderWithSequencedTaskRunner(&mdps[2], task_runner2,
+                                              kDefaultOptions);
+  // |mdps[0]| should be disabled permanently after first dump.
+  EXPECT_CALL(mdps[0], OnMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdps[1], OnMemoryDump(_, _)).Times(2);
+  EXPECT_CALL(mdps[2], OnMemoryDump(_, _)).Times(2);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  task_runner1->set_enabled(false);
+  last_callback_success_ = false;
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  // Tasks should be individually posted even if |mdps[1]| and |mdps[2]| belong
+  // to same task runner.
+  EXPECT_EQ(1u, task_runner1->no_of_post_tasks());
+  EXPECT_EQ(2u, task_runner2->no_of_post_tasks());
+  EXPECT_TRUE(last_callback_success_);
+
+  task_runner1->set_enabled(true);
+  last_callback_success_ = false;
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  EXPECT_EQ(2u, task_runner1->no_of_post_tasks());
+  EXPECT_EQ(4u, task_runner2->no_of_post_tasks());
+  EXPECT_TRUE(last_callback_success_);
+  DisableTracing();
+}
+
+// Checks that providers get disabled after 3 consecutive failures, but not
+// otherwise (e.g., if interleaved).
+TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+
+  RegisterDumpProvider(&mdp1);
+  RegisterDumpProvider(&mdp2);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+      .Times(GetMaxConsecutiveFailuresCount())
+      .WillRepeatedly(Return(false));
+
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true))
+      .WillOnce(Return(false))
+      .WillOnce(Return(false))
+      .WillOnce(Return(true))
+      .WillOnce(Return(false));
+
+  for (int i = 0; i < kNumDumps; i++) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+
+  DisableTracing();
+}
+
+// Sneakily registers an extra memory dump provider while an existing one is
+// dumping and expect it to take part in the already active tracing session.
+TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+
+  RegisterDumpProvider(&mdp1);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+      .Times(4)
+      .WillOnce(Return(true))
+      .WillOnce(
+          Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+            RegisterDumpProvider(&mdp2);
+            return true;
+          }))
+      .WillRepeatedly(Return(true));
+
+  // Depending on the insertion order (before or after mdp1), mdp2 might be
+  // called also immediately after it gets registered.
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+      .Times(Between(2, 3))
+      .WillRepeatedly(Return(true));
+
+  for (int i = 0; i < 4; i++) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+
+  DisableTracing();
+}
+
+// Like RegisterDumperWhileDumping, but unregister the dump provider instead.
+TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  MockMemoryDumpProvider mdp2;
+
+  RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
+  RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _))
+      .Times(4)
+      .WillOnce(Return(true))
+      .WillOnce(
+          Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+            MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2);
+            return true;
+          }))
+      .WillRepeatedly(Return(true));
+
+  // Depending on the insertion order (before or after mdp1), mdp2 might have
+  // been already called when UnregisterDumpProvider happens.
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _))
+      .Times(Between(1, 2))
+      .WillRepeatedly(Return(true));
+
+  for (int i = 0; i < 4; i++) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+
+  DisableTracing();
+}
+
+// Checks that the dump does not abort when unregistering a provider while
+// dumping from a different thread than the dumping thread.
+TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  std::vector<std::unique_ptr<TestIOThread>> threads;
+  std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
+
+  for (int i = 0; i < 2; i++) {
+    threads.push_back(
+        WrapUnique(new TestIOThread(TestIOThread::kAutoStart)));
+    mdps.push_back(WrapUnique(new MockMemoryDumpProvider()));
+    RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
+                         kDefaultOptions);
+  }
+
+  int on_memory_dump_call_count = 0;
+
+  // When OnMemoryDump is called on either of the dump providers, it will
+  // unregister the other one.
+  for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) {
+    int other_idx = (mdps.front() == mdp);
+    TestIOThread* other_thread = threads[other_idx].get();
+    MockMemoryDumpProvider* other_mdp = mdps[other_idx].get();
+    auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
+        const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
+      other_thread->PostTaskAndWait(
+          FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider,
+                                base::Unretained(&*mdm_), other_mdp));
+      on_memory_dump_call_count++;
+      return true;
+    };
+
+    // OnMemoryDump is called once for the provider that dumps first, and zero
+    // times for the other provider.
+    EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+        .Times(AtMost(1))
+        .WillOnce(Invoke(on_dump));
+  }
+
+  last_callback_success_ = false;
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  ASSERT_EQ(1, on_memory_dump_call_count);
+  ASSERT_TRUE(last_callback_success_);
+
+  DisableTracing();
+}
+
+// If a thread (with a dump provider living on it) is torn down during a dump
+// its dump provider should be skipped but the dump itself should succeed.
+TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  std::vector<std::unique_ptr<TestIOThread>> threads;
+  std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps;
+
+  for (int i = 0; i < 2; i++) {
+    threads.push_back(
+        WrapUnique(new TestIOThread(TestIOThread::kAutoStart)));
+    mdps.push_back(WrapUnique(new MockMemoryDumpProvider()));
+    RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
+                         kDefaultOptions);
+  }
+
+  int on_memory_dump_call_count = 0;
+
+  // When OnMemoryDump is called on either of the dump providers, it will
+  // tear down the thread of the other one.
+  for (const std::unique_ptr<MockMemoryDumpProvider>& mdp : mdps) {
+    int other_idx = (mdps.front() == mdp);
+    TestIOThread* other_thread = threads[other_idx].get();
+    auto on_dump = [other_thread, &on_memory_dump_call_count](
+        const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
+      other_thread->Stop();
+      on_memory_dump_call_count++;
+      return true;
+    };
+
+    // OnMemoryDump is called once for the provider that dumps first, and zero
+    // times for the other provider.
+    EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+        .Times(AtMost(1))
+        .WillOnce(Invoke(on_dump));
+  }
+
+  last_callback_success_ = false;
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  ASSERT_EQ(1, on_memory_dump_call_count);
+  ASSERT_TRUE(last_callback_success_);
+
+  DisableTracing();
+}
+
+// Checks that a NACK callback is invoked if RequestGlobalDump() is called when
+// tracing is not enabled.
+TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MockMemoryDumpProvider mdp1;
+  RegisterDumpProvider(&mdp1);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
+
+  last_callback_success_ = true;
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  EXPECT_FALSE(last_callback_success_);
+}
+
+// Checks that is the MemoryDumpManager is initialized after tracing already
+// began, it will still late-join the party (real use case: startup tracing).
+TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
+  MockMemoryDumpProvider mdp;
+  RegisterDumpProvider(&mdp);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  // First check that a RequestGlobalDump() issued before the MemoryDumpManager
+  // initialization gets NACK-ed cleanly.
+  {
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    EXPECT_FALSE(last_callback_success_);
+  }
+
+  // Now late-initialize the MemoryDumpManager and check that the
+  // RequestGlobalDump completes successfully.
+  {
+    EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
+    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+    InitializeMemoryDumpManager(false /* is_coordinator */);
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+    EXPECT_TRUE(last_callback_success_);
+  }
+  DisableTracing();
+}
+
+// This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
+// expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
+// dumps in memory-infra, handling gracefully the transition between the legacy
+// and the new-style (JSON-based) TraceConfig.
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+
+  // Don't trigger the default behavior of the mock delegate in this test,
+  // which would short-circuit the dump request to the actual
+  // CreateProcessDump().
+  // We don't want to create any dump in this test, only check whether the dumps
+  // are requested or not.
+  ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
+
+  // Enabling memory-infra in a non-coordinator process should not trigger any
+  // periodic dumps.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
+  // process with a fully defined trigger config should NOT enable any periodic
+  // dumps.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
+  InitializeMemoryDumpManager(true /* is_coordinator */);
+  MemoryDumpManagerDelegateForTesting& delegate = *delegate_;
+  ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return());
+
+  // Enabling memory-infra with the legacy TraceConfig (category filter) in
+  // a coordinator process should enable periodic dumps.
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process without specifying any "memory_dump_config" section should enable
+  // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
+  // is: ticking memory-infra should dump periodically with the default config.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
+  EXPECT_TRUE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with an empty "memory_dump_config" should NOT enable periodic
+  // dumps. This is the way telemetry is supposed to use memory-infra with
+  // only explicitly triggered dumps.
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  DisableTracing();
+
+  // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
+  // process with a fully defined trigger config should cause periodic dumps to
+  // be performed in the correct order.
+  RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+
+  const int kHeavyDumpRate = 5;
+  const int kLightDumpPeriodMs = 1;
+  const int kHeavyDumpPeriodMs = kHeavyDumpRate * kLightDumpPeriodMs;
+  // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
+  testing::InSequence sequence;
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .Times(kHeavyDumpRate - 1);
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsDetailedDump(), _));
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .Times(kHeavyDumpRate - 2);
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLightDump(), _))
+      .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
+                                      const MemoryDumpCallback& callback) {
+        ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
+      }));
+
+  // Swallow all the final spurious calls until tracing gets disabled.
+  EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
+
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
+          kLightDumpPeriodMs, kHeavyDumpPeriodMs));
+  run_loop.Run();
+  DisableTracing();
+}
+
+// Tests against race conditions that might arise when disabling tracing in the
+// middle of a global memory dump.
+TEST_F(MemoryDumpManagerTest, DisableTracingWhileDumping) {
+  base::WaitableEvent tracing_disabled_event(
+      WaitableEvent::ResetPolicy::AUTOMATIC,
+      WaitableEvent::InitialState::NOT_SIGNALED);
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+
+  // Register a bound dump provider.
+  std::unique_ptr<Thread> mdp_thread(new Thread("test thread"));
+  mdp_thread->Start();
+  MockMemoryDumpProvider mdp_with_affinity;
+  RegisterDumpProvider(&mdp_with_affinity, mdp_thread->task_runner(),
+                       kDefaultOptions);
+
+  // Register also an unbound dump provider. Unbound dump providers are always
+  // invoked after bound ones.
+  MockMemoryDumpProvider unbound_mdp;
+  RegisterDumpProvider(&unbound_mdp, nullptr, kDefaultOptions);
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp_with_affinity, OnMemoryDump(_, _))
+      .Times(1)
+      .WillOnce(
+          Invoke([&tracing_disabled_event](const MemoryDumpArgs&,
+                                           ProcessMemoryDump* pmd) -> bool {
+            tracing_disabled_event.Wait();
+
+            // At this point tracing has been disabled and the
+            // MemoryDumpManager.dump_thread_ has been shut down.
+            return true;
+          }));
+
+  // |unbound_mdp| should never be invoked because the thread for unbound dump
+  // providers has been shutdown in the meanwhile.
+  EXPECT_CALL(unbound_mdp, OnMemoryDump(_, _)).Times(0);
+
+  last_callback_success_ = true;
+  RunLoop run_loop;
+  MemoryDumpCallback callback =
+      Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+           ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure());
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                          MemoryDumpLevelOfDetail::DETAILED, callback);
+  DisableTracing();
+  tracing_disabled_event.Signal();
+  run_loop.Run();
+
+  EXPECT_FALSE(last_callback_success_);
+}
+
+// Tests against race conditions that can happen if tracing is disabled before
+// the CreateProcessDump() call. Real-world regression: crbug.com/580295 .
+TEST_F(MemoryDumpManagerTest, DisableTracingRightBeforeStartOfDump) {
+  base::WaitableEvent tracing_disabled_event(
+      WaitableEvent::ResetPolicy::AUTOMATIC,
+      WaitableEvent::InitialState::NOT_SIGNALED);
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+
+  std::unique_ptr<Thread> mdp_thread(new Thread("test thread"));
+  mdp_thread->Start();
+
+  // Create both same-thread MDP and another MDP with dedicated thread
+  MockMemoryDumpProvider mdp1;
+  RegisterDumpProvider(&mdp1);
+  MockMemoryDumpProvider mdp2;
+  RegisterDumpProvider(&mdp2, mdp_thread->task_runner(), kDefaultOptions);
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _))
+      .WillOnce(Invoke([this](const MemoryDumpRequestArgs& args,
+                              const MemoryDumpCallback& callback) {
+        DisableTracing();
+        delegate_->CreateProcessDump(args, callback);
+      }));
+
+  // If tracing is disabled for current session CreateProcessDump() should NOT
+  // request dumps from providers. Real-world regression: crbug.com/600570 .
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
+
+  last_callback_success_ = true;
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  EXPECT_FALSE(last_callback_success_);
+}
+
+TEST_F(MemoryDumpManagerTest, DumpOnBehalfOfOtherProcess) {
+  using trace_analyzer::Query;
+
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+
+  // Standard provider with default options (create dump for current process).
+  MemoryDumpProvider::Options options;
+  MockMemoryDumpProvider mdp1;
+  RegisterDumpProvider(&mdp1, nullptr, options);
+
+  // Provider with out-of-process dumping.
+  MockMemoryDumpProvider mdp2;
+  options.target_pid = 123;
+  RegisterDumpProvider(&mdp2, nullptr, options);
+
+  // Another provider with out-of-process dumping.
+  MockMemoryDumpProvider mdp3;
+  options.target_pid = 456;
+  RegisterDumpProvider(&mdp3, nullptr, options);
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+  EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  DisableTracing();
+
+  // Flush the trace into JSON.
+  trace_event::TraceResultBuffer buffer;
+  TraceResultBuffer::SimpleOutput trace_output;
+  buffer.SetOutputCallback(trace_output.GetCallback());
+  RunLoop run_loop;
+  buffer.Start();
+  trace_event::TraceLog::GetInstance()->Flush(
+      Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
+  run_loop.Run();
+  buffer.Finish();
+
+  // Analyze the JSON.
+  std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer = WrapUnique(
+      trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
+  trace_analyzer::TraceEventVector events;
+  analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
+                       &events);
+
+  ASSERT_EQ(3u, events.size());
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123)));
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456)));
+  ASSERT_EQ(1u, trace_analyzer::CountMatches(
+                    events, Query::EventPidIs(GetCurrentProcId())));
+  ASSERT_EQ(events[0]->id, events[1]->id);
+  ASSERT_EQ(events[0]->id, events[2]->id);
+}
+
+// Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the
+// unregistration should actually delete the providers and not leak them.
+TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  static const int kNumProviders = 3;
+  int dtor_count = 0;
+  std::vector<std::unique_ptr<MemoryDumpProvider>> mdps;
+  for (int i = 0; i < kNumProviders; ++i) {
+    std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
+    mdp->enable_mock_destructor = true;
+    EXPECT_CALL(*mdp, Destructor())
+        .WillOnce(Invoke([&dtor_count]() { dtor_count++; }));
+    RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
+    mdps.push_back(std::move(mdp));
+  }
+
+  while (!mdps.empty()) {
+    mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back()));
+    mdps.pop_back();
+  }
+
+  ASSERT_EQ(kNumProviders, dtor_count);
+}
+
+// This test checks against races when unregistering an unbound dump provider
+// from another thread while dumping. It registers one MDP and, when
+// OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon()
+// from another thread. The OnMemoryDump() and the dtor call are expected to
+// happen on the same thread (the MemoryDumpManager utility thread).
+TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
+  mdp->enable_mock_destructor = true;
+  RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
+
+  base::PlatformThreadRef thread_ref;
+  auto self_unregister_from_another_thread = [&mdp, &thread_ref](
+      const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+    thread_ref = PlatformThread::CurrentRef();
+    TestIOThread thread_for_unregistration(TestIOThread::kAutoStart);
+    thread_for_unregistration.PostTaskAndWait(
+        FROM_HERE,
+        base::Bind(
+            &MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
+            base::Unretained(MemoryDumpManager::GetInstance()),
+            base::Passed(std::unique_ptr<MemoryDumpProvider>(std::move(mdp)))));
+    thread_for_unregistration.Stop();
+    return true;
+  };
+  EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+      .Times(1)
+      .WillOnce(Invoke(self_unregister_from_another_thread));
+  EXPECT_CALL(*mdp, Destructor())
+      .Times(1)
+      .WillOnce(Invoke([&thread_ref]() {
+        EXPECT_EQ(thread_ref, PlatformThread::CurrentRef());
+      }));
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
+  for (int i = 0; i < 2; ++i) {
+    RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                             MemoryDumpLevelOfDetail::DETAILED);
+  }
+  DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, TestWhitelistingMDP) {
+  InitializeMemoryDumpManager(false /* is_coordinator */);
+  SetDumpProviderWhitelistForTesting(kTestMDPWhitelist);
+  std::unique_ptr<MockMemoryDumpProvider> mdp1(new MockMemoryDumpProvider);
+  RegisterDumpProvider(mdp1.get());
+  std::unique_ptr<MockMemoryDumpProvider> mdp2(new MockMemoryDumpProvider);
+  RegisterDumpProvider(mdp2.get(), nullptr, kDefaultOptions,
+                       kWhitelistedMDPName);
+
+  EXPECT_CALL(*mdp1, OnMemoryDump(_, _)).Times(0);
+  EXPECT_CALL(*mdp2, OnMemoryDump(_, _)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+
+  EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+  EXPECT_FALSE(IsPeriodicDumpingEnabled());
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::BACKGROUND);
+  DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, TestBackgroundTracingSetup) {
+  InitializeMemoryDumpManager(true /* is_coordinator */);
+
+  RunLoop run_loop;
+  auto quit_closure = run_loop.QuitClosure();
+
+  testing::InSequence sequence;
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(IsBackgroundDump(), _))
+      .Times(5);
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(IsBackgroundDump(), _))
+      .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args,
+                                      const MemoryDumpCallback& callback) {
+        ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure);
+      }));
+  EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(AnyNumber());
+
+  EnableTracingWithTraceConfig(
+      TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger(
+          1 /* period_ms */));
+
+  // Only background mode dumps should be allowed with the trace config.
+  last_callback_success_ = false;
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::LIGHT);
+  EXPECT_FALSE(last_callback_success_);
+  last_callback_success_ = false;
+  RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+                           MemoryDumpLevelOfDetail::DETAILED);
+  EXPECT_FALSE(last_callback_success_);
+
+  ASSERT_TRUE(IsPeriodicDumpingEnabled());
+  run_loop.Run();
+  DisableTracing();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/memory_dump_provider.h b/libchrome/base/trace_event/memory_dump_provider.h
new file mode 100644
index 0000000..2c50286
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_provider.h
@@ -0,0 +1,64 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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"
+#include "base/process/process_handle.h"
+#include "base/trace_event/memory_dump_request_args.h"
+
+namespace base {
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// The contract interface that memory dump providers must implement.
+class BASE_EXPORT MemoryDumpProvider {
+ public:
+  // Optional arguments for MemoryDumpManager::RegisterDumpProvider().
+  struct Options {
+    Options()
+        : target_pid(kNullProcessId),
+          dumps_on_single_thread_task_runner(false) {}
+
+    // If the dump provider generates dumps on behalf of another process,
+    // |target_pid| contains the pid of that process.
+    // The default value is kNullProcessId, which means that the dump provider
+    // generates dumps for the current process.
+    ProcessId target_pid;
+
+    // |dumps_on_single_thread_task_runner| is true if the dump provider runs on
+    // a SingleThreadTaskRunner, which is usually the case. It is faster to run
+    // all providers that run on the same thread together without thread hops.
+    bool dumps_on_single_thread_task_runner;
+  };
+
+  virtual ~MemoryDumpProvider() {}
+
+  // Called by the MemoryDumpManager when generating memory dumps.
+  // The |args| specify if the embedder should generate light/heavy dumps on
+  // dump requests. 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(const MemoryDumpArgs& args,
+                            ProcessMemoryDump* pmd) = 0;
+
+  // Called by the MemoryDumpManager when an allocator should start or stop
+  // collecting extensive allocation data, if supported.
+  virtual void OnHeapProfilingEnabled(bool) {}
+
+ protected:
+  MemoryDumpProvider() {}
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
diff --git a/libchrome/base/trace_event/memory_dump_request_args.cc b/libchrome/base/trace_event/memory_dump_request_args.cc
new file mode 100644
index 0000000..e6c5b87
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_request_args.cc
@@ -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.
+
+#include "base/trace_event/memory_dump_request_args.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+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::EXPLICITLY_TRIGGERED:
+      return "explicitly_triggered";
+  }
+  NOTREACHED();
+  return "unknown";
+}
+
+const char* MemoryDumpLevelOfDetailToString(
+    const MemoryDumpLevelOfDetail& level_of_detail) {
+  switch (level_of_detail) {
+    case MemoryDumpLevelOfDetail::BACKGROUND:
+      return "background";
+    case MemoryDumpLevelOfDetail::LIGHT:
+      return "light";
+    case MemoryDumpLevelOfDetail::DETAILED:
+      return "detailed";
+  }
+  NOTREACHED();
+  return "unknown";
+}
+
+MemoryDumpLevelOfDetail StringToMemoryDumpLevelOfDetail(
+    const std::string& str) {
+  if (str == "background")
+    return MemoryDumpLevelOfDetail::BACKGROUND;
+  if (str == "light")
+    return MemoryDumpLevelOfDetail::LIGHT;
+  if (str == "detailed")
+    return MemoryDumpLevelOfDetail::DETAILED;
+  NOTREACHED();
+  return MemoryDumpLevelOfDetail::LAST;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/memory_dump_request_args.h b/libchrome/base/trace_event/memory_dump_request_args.h
new file mode 100644
index 0000000..f3ff9d8
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_request_args.h
@@ -0,0 +1,84 @@
+// 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 <stdint.h>
+#include <string>
+
+#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.
+  EXPLICITLY_TRIGGERED,  // Non maskable dump request.
+  LAST = EXPLICITLY_TRIGGERED // For IPC macros.
+};
+
+// Tells the MemoryDumpProvider(s) how much detailed their dumps should be.
+enum class MemoryDumpLevelOfDetail : uint32_t {
+  FIRST,
+
+  // For background tracing mode. The dump time is quick, and typically just the
+  // totals are expected. Suballocations need not be specified. Dump name must
+  // contain only pre-defined strings and string arguments cannot be added.
+  BACKGROUND = FIRST,
+
+  // For the levels below, MemoryDumpProvider instances must guarantee that the
+  // total size reported in the root node is consistent. Only the granularity of
+  // the child MemoryAllocatorDump(s) differs with the levels.
+
+  // Few entries, typically a fixed number, per dump.
+  LIGHT,
+
+  // Unrestricted amount of entries per dump.
+  DETAILED,
+
+  LAST = DETAILED
+};
+
+// Initial request arguments for a global memory dump. (see
+// MemoryDumpManager::RequestGlobalMemoryDump()).
+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_t dump_guid;
+
+  MemoryDumpType dump_type;
+  MemoryDumpLevelOfDetail level_of_detail;
+};
+
+// Args for ProcessMemoryDump and passed to OnMemoryDump calls for memory dump
+// providers. Dump providers are expected to read the args for creating dumps.
+struct MemoryDumpArgs {
+  // Specifies how detailed the dumps should be.
+  MemoryDumpLevelOfDetail level_of_detail;
+};
+
+using MemoryDumpCallback = Callback<void(uint64_t dump_guid, bool success)>;
+
+BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
+
+BASE_EXPORT const char* MemoryDumpLevelOfDetailToString(
+    const MemoryDumpLevelOfDetail& level_of_detail);
+
+BASE_EXPORT MemoryDumpLevelOfDetail
+StringToMemoryDumpLevelOfDetail(const std::string& str);
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
diff --git a/libchrome/base/trace_event/memory_dump_session_state.cc b/libchrome/base/trace_event/memory_dump_session_state.cc
new file mode 100644
index 0000000..b3d9a8c
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_session_state.cc
@@ -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.
+
+#include "base/trace_event/memory_dump_session_state.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryDumpSessionState::MemoryDumpSessionState() {}
+
+MemoryDumpSessionState::~MemoryDumpSessionState() {}
+
+void MemoryDumpSessionState::SetStackFrameDeduplicator(
+    std::unique_ptr<StackFrameDeduplicator> stack_frame_deduplicator) {
+  DCHECK(!stack_frame_deduplicator_);
+  stack_frame_deduplicator_ = std::move(stack_frame_deduplicator);
+}
+
+void MemoryDumpSessionState::SetTypeNameDeduplicator(
+    std::unique_ptr<TypeNameDeduplicator> type_name_deduplicator) {
+  DCHECK(!type_name_deduplicator_);
+  type_name_deduplicator_ = std::move(type_name_deduplicator);
+}
+
+void MemoryDumpSessionState::SetMemoryDumpConfig(
+    const TraceConfig::MemoryDumpConfig& config) {
+  memory_dump_config_ = config;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/memory_dump_session_state.h b/libchrome/base/trace_event/memory_dump_session_state.h
new file mode 100644
index 0000000..f199ec1
--- /dev/null
+++ b/libchrome/base/trace_event/memory_dump_session_state.h
@@ -0,0 +1,69 @@
+// 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 <memory>
+
+#include "base/base_export.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/trace_config.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();
+
+  // Returns the stack frame deduplicator that should be used by memory dump
+  // providers when doing a heap dump.
+  StackFrameDeduplicator* stack_frame_deduplicator() const {
+    return stack_frame_deduplicator_.get();
+  }
+
+  void SetStackFrameDeduplicator(
+      std::unique_ptr<StackFrameDeduplicator> stack_frame_deduplicator);
+
+  // Returns the type name deduplicator that should be used by memory dump
+  // providers when doing a heap dump.
+  TypeNameDeduplicator* type_name_deduplicator() const {
+    return type_name_deduplicator_.get();
+  }
+
+  void SetTypeNameDeduplicator(
+      std::unique_ptr<TypeNameDeduplicator> type_name_deduplicator);
+
+  const TraceConfig::MemoryDumpConfig& memory_dump_config() const {
+    return memory_dump_config_;
+  }
+
+  void SetMemoryDumpConfig(const TraceConfig::MemoryDumpConfig& config);
+
+ private:
+  friend class RefCountedThreadSafe<MemoryDumpSessionState>;
+  ~MemoryDumpSessionState();
+
+  // Deduplicates backtraces in heap dumps so they can be written once when the
+  // trace is finalized.
+  std::unique_ptr<StackFrameDeduplicator> stack_frame_deduplicator_;
+
+  // Deduplicates type names in heap dumps so they can be written once when the
+  // trace is finalized.
+  std::unique_ptr<TypeNameDeduplicator> type_name_deduplicator_;
+
+  // The memory dump config, copied at the time when the tracing session was
+  // started.
+  TraceConfig::MemoryDumpConfig memory_dump_config_;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
diff --git a/libchrome/base/trace_event/memory_infra_background_whitelist.cc b/libchrome/base/trace_event/memory_infra_background_whitelist.cc
new file mode 100644
index 0000000..aed187f
--- /dev/null
+++ b/libchrome/base/trace_event/memory_infra_background_whitelist.cc
@@ -0,0 +1,131 @@
+// Copyright 2016 The Chromium Authors. All 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_infra_background_whitelist.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include <string>
+
+namespace base {
+namespace trace_event {
+namespace {
+
+// The names of dump providers whitelisted for background tracing. Dump
+// providers can be added here only if the background mode dump has very
+// less performance and memory overhead.
+const char* const kDumpProviderWhitelist[] = {
+    "BlinkGC",
+    "ChildDiscardableSharedMemoryManager",
+    "DOMStorage",
+    "HostDiscardableSharedMemoryManager",
+    "IndexedDBBackingStore",
+    "JavaHeap",
+    "LeveldbValueStore",
+    "Malloc",
+    "PartitionAlloc",
+    "ProcessMemoryMetrics",
+    "Skia",
+    "Sql",
+    "V8Isolate",
+    "WinHeap",
+    nullptr  // End of list marker.
+};
+
+// A list of string names that are allowed for the memory allocator dumps in
+// background mode.
+const char* const kAllocatorDumpNameWhitelist[] = {
+    "blink_gc",
+    "blink_gc/allocated_objects",
+    "discardable",
+    "discardable/child_0x?",
+    "dom_storage/0x?/cache_size",
+    "dom_storage/session_storage_0x?",
+    "java_heap",
+    "java_heap/allocated_objects",
+    "leveldb/index_db/0x?",
+    "leveldb/value_store/Extensions.Database.Open.Settings/0x?",
+    "leveldb/value_store/Extensions.Database.Open.Rules/0x?",
+    "leveldb/value_store/Extensions.Database.Open.State/0x?",
+    "leveldb/value_store/Extensions.Database.Open/0x?",
+    "leveldb/value_store/Extensions.Database.Restore/0x?",
+    "leveldb/value_store/Extensions.Database.Value.Restore/0x?",
+    "malloc",
+    "malloc/allocated_objects",
+    "malloc/metadata_fragmentation_caches",
+    "partition_alloc/allocated_objects",
+    "partition_alloc/partitions",
+    "partition_alloc/partitions/buffer",
+    "partition_alloc/partitions/fast_malloc",
+    "partition_alloc/partitions/layout",
+    "skia/sk_glyph_cache",
+    "skia/sk_resource_cache",
+    "sqlite",
+    "v8/isolate_0x?/heap_spaces",
+    "v8/isolate_0x?/heap_spaces/code_space",
+    "v8/isolate_0x?/heap_spaces/large_object_space",
+    "v8/isolate_0x?/heap_spaces/map_space",
+    "v8/isolate_0x?/heap_spaces/new_space",
+    "v8/isolate_0x?/heap_spaces/old_space",
+    "v8/isolate_0x?/heap_spaces/other_spaces",
+    "v8/isolate_0x?/malloc",
+    "v8/isolate_0x?/zapped_for_debug",
+    "winheap",
+    "winheap/allocated_objects",
+    nullptr  // End of list marker.
+};
+
+const char* const* g_dump_provider_whitelist = kDumpProviderWhitelist;
+const char* const* g_allocator_dump_name_whitelist =
+    kAllocatorDumpNameWhitelist;
+
+}  // namespace
+
+bool IsMemoryDumpProviderWhitelisted(const char* mdp_name) {
+  for (size_t i = 0; g_dump_provider_whitelist[i] != nullptr; ++i) {
+    if (strcmp(mdp_name, g_dump_provider_whitelist[i]) == 0)
+      return true;
+  }
+  return false;
+}
+
+bool IsMemoryAllocatorDumpNameWhitelisted(const std::string& name) {
+  // Remove special characters, numbers (including hexadecimal which are marked
+  // by '0x') from the given string.
+  const size_t length = name.size();
+  std::string stripped_str;
+  stripped_str.reserve(length);
+  bool parsing_hex = false;
+  for (size_t i = 0; i < length; ++i) {
+    if (parsing_hex && isxdigit(name[i]))
+      continue;
+    parsing_hex = false;
+    if (i + 1 < length && name[i] == '0' && name[i + 1] == 'x') {
+      parsing_hex = true;
+      stripped_str.append("0x?");
+      ++i;
+    } else {
+      stripped_str.push_back(name[i]);
+    }
+  }
+
+  for (size_t i = 0; g_allocator_dump_name_whitelist[i] != nullptr; ++i) {
+    if (stripped_str == g_allocator_dump_name_whitelist[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void SetDumpProviderWhitelistForTesting(const char* const* list) {
+  g_dump_provider_whitelist = list;
+}
+
+void SetAllocatorDumpNameWhitelistForTesting(const char* const* list) {
+  g_allocator_dump_name_whitelist = list;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/memory_infra_background_whitelist.h b/libchrome/base/trace_event/memory_infra_background_whitelist.h
new file mode 100644
index 0000000..b8d704a
--- /dev/null
+++ b/libchrome/base/trace_event/memory_infra_background_whitelist.h
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Authors. All 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_INFRA_BACKGROUND_WHITELIST_H_
+#define BASE_TRACE_EVENT_MEMORY_INFRA_BACKGROUND_WHITELIST_H_
+
+// This file contains the whitelists for background mode to limit the tracing
+// overhead and remove sensitive information from traces.
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace trace_event {
+
+// Checks if the given |mdp_name| is in the whitelist.
+bool BASE_EXPORT IsMemoryDumpProviderWhitelisted(const char* mdp_name);
+
+// Checks if the given |name| matches any of the whitelisted patterns.
+bool BASE_EXPORT IsMemoryAllocatorDumpNameWhitelisted(const std::string& name);
+
+// The whitelist is replaced with the given list for tests. The last element of
+// the list must be nullptr.
+void BASE_EXPORT SetDumpProviderWhitelistForTesting(const char* const* list);
+void BASE_EXPORT
+SetAllocatorDumpNameWhitelistForTesting(const char* const* list);
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_INFRA_BACKGROUND_WHITELIST_H_
diff --git a/libchrome/base/trace_event/process_memory_dump.cc b/libchrome/base/trace_event/process_memory_dump.cc
new file mode 100644
index 0000000..8269892
--- /dev/null
+++ b/libchrome/base/trace_event/process_memory_dump.cc
@@ -0,0 +1,373 @@
+// 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 <errno.h>
+
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/heap_profiler_heap_dump_writer.h"
+#include "base/trace_event/memory_infra_background_whitelist.h"
+#include "base/trace_event/process_memory_totals.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#if defined(OS_IOS)
+#include <sys/sysctl.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
+
+#if defined(OS_WIN)
+#include <Psapi.h>
+#endif
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+const char kEdgeTypeOwnership[] = "ownership";
+
+std::string GetSharedGlobalAllocatorDumpName(
+    const MemoryAllocatorDumpGuid& guid) {
+  return "global/" + guid.ToString();
+}
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+size_t GetSystemPageCount(size_t mapped_size, size_t page_size) {
+  return (mapped_size + page_size - 1) / page_size;
+}
+#endif
+
+}  // namespace
+
+// static
+bool ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = false;
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+// static
+size_t ProcessMemoryDump::GetSystemPageSize() {
+#if defined(OS_IOS)
+  // On iOS, getpagesize() returns the user page sizes, but for allocating
+  // arrays for mincore(), kernel page sizes is needed. sysctlbyname() should
+  // be used for this. Refer to crbug.com/542671 and Apple rdar://23651782
+  int pagesize;
+  size_t pagesize_len;
+  int status = sysctlbyname("vm.pagesize", NULL, &pagesize_len, nullptr, 0);
+  if (!status && pagesize_len == sizeof(pagesize)) {
+    if (!sysctlbyname("vm.pagesize", &pagesize, &pagesize_len, nullptr, 0))
+      return pagesize;
+  }
+  LOG(ERROR) << "sysctlbyname(\"vm.pagesize\") failed.";
+  // Falls back to getpagesize() although it may be wrong in certain cases.
+#endif  // defined(OS_IOS)
+  return base::GetPageSize();
+}
+
+// static
+size_t ProcessMemoryDump::CountResidentBytes(void* start_address,
+                                             size_t mapped_size) {
+  const size_t page_size = GetSystemPageSize();
+  const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address);
+  DCHECK_EQ(0u, start_pointer % page_size);
+
+  size_t offset = 0;
+  size_t total_resident_size = 0;
+  bool failure = false;
+
+  // An array as large as number of pages in memory segment needs to be passed
+  // to the query function. To avoid allocating a large array, the given block
+  // of memory is split into chunks of size |kMaxChunkSize|.
+  const size_t kMaxChunkSize = 8 * 1024 * 1024;
+  size_t max_vec_size =
+      GetSystemPageCount(std::min(mapped_size, kMaxChunkSize), page_size);
+#if defined(OS_MACOSX) || defined(OS_IOS)
+  std::unique_ptr<char[]> vec(new char[max_vec_size]);
+#elif defined(OS_WIN)
+  std::unique_ptr<PSAPI_WORKING_SET_EX_INFORMATION[]> vec(
+      new PSAPI_WORKING_SET_EX_INFORMATION[max_vec_size]);
+#elif defined(OS_POSIX)
+  std::unique_ptr<unsigned char[]> vec(new unsigned char[max_vec_size]);
+#endif
+
+  while (offset < mapped_size) {
+    uintptr_t chunk_start = (start_pointer + offset);
+    const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize);
+    const size_t page_count = GetSystemPageCount(chunk_size, page_size);
+    size_t resident_page_count = 0;
+
+#if defined(OS_MACOSX) || defined(OS_IOS)
+    // mincore in MAC does not fail with EAGAIN.
+    failure =
+        !!mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get());
+    for (size_t i = 0; i < page_count; i++)
+      resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0;
+#elif defined(OS_WIN)
+    for (size_t i = 0; i < page_count; i++) {
+      vec[i].VirtualAddress =
+          reinterpret_cast<void*>(chunk_start + i * page_size);
+    }
+    DWORD vec_size = static_cast<DWORD>(
+        page_count * sizeof(PSAPI_WORKING_SET_EX_INFORMATION));
+    failure = !QueryWorkingSetEx(GetCurrentProcess(), vec.get(), vec_size);
+
+    for (size_t i = 0; i < page_count; i++)
+      resident_page_count += vec[i].VirtualAttributes.Valid;
+#elif defined(OS_POSIX)
+    int error_counter = 0;
+    int result = 0;
+    // HANDLE_EINTR tries for 100 times. So following the same pattern.
+    do {
+      result =
+          mincore(reinterpret_cast<void*>(chunk_start), chunk_size, vec.get());
+    } while (result == -1 && errno == EAGAIN && error_counter++ < 100);
+    failure = !!result;
+
+    for (size_t i = 0; i < page_count; i++)
+      resident_page_count += vec[i] & 1;
+#endif
+
+    if (failure)
+      break;
+
+    total_resident_size += resident_page_count * page_size;
+    offset += kMaxChunkSize;
+  }
+
+  DCHECK(!failure);
+  if (failure) {
+    total_resident_size = 0;
+    LOG(ERROR) << "CountResidentBytes failed. The resident size is invalid";
+  }
+  return total_resident_size;
+}
+#endif  // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
+ProcessMemoryDump::ProcessMemoryDump(
+    scoped_refptr<MemoryDumpSessionState> session_state,
+    const MemoryDumpArgs& dump_args)
+    : has_process_totals_(false),
+      has_process_mmaps_(false),
+      session_state_(std::move(session_state)),
+      dump_args_(dump_args) {}
+
+ProcessMemoryDump::~ProcessMemoryDump() {}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+    const std::string& absolute_name) {
+  return AddAllocatorDumpInternal(
+      WrapUnique(new MemoryAllocatorDump(absolute_name, this)));
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+    const std::string& absolute_name,
+    const MemoryAllocatorDumpGuid& guid) {
+  return AddAllocatorDumpInternal(
+      WrapUnique(new MemoryAllocatorDump(absolute_name, this, guid)));
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::AddAllocatorDumpInternal(
+    std::unique_ptr<MemoryAllocatorDump> mad) {
+  // In background mode return the black hole dump, if invalid dump name is
+  // given.
+  if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND &&
+      !IsMemoryAllocatorDumpNameWhitelisted(mad->absolute_name())) {
+    return GetBlackHoleMad();
+  }
+
+  auto insertion_result = allocator_dumps_.insert(
+      std::make_pair(mad->absolute_name(), std::move(mad)));
+  MemoryAllocatorDump* inserted_mad = insertion_result.first->second.get();
+  DCHECK(insertion_result.second) << "Duplicate name: "
+                                  << inserted_mad->absolute_name();
+  return inserted_mad;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
+    const std::string& absolute_name) const {
+  auto it = allocator_dumps_.find(absolute_name);
+  if (it != allocator_dumps_.end())
+    return it->second.get();
+  if (black_hole_mad_)
+    return black_hole_mad_.get();
+  return nullptr;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump(
+    const std::string& absolute_name) {
+  MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name);
+  return mad ? mad : CreateAllocatorDump(absolute_name);
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump(
+    const MemoryAllocatorDumpGuid& guid) {
+  // Global dumps are disabled in background mode.
+  if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND)
+    return GetBlackHoleMad();
+
+  // A shared allocator dump can be shared within a process and the guid could
+  // have been created already.
+  MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid);
+  if (mad) {
+    // The weak flag is cleared because this method should create a non-weak
+    // dump.
+    mad->clear_flags(MemoryAllocatorDump::Flags::WEAK);
+    return mad;
+  }
+  return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid);
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateWeakSharedGlobalAllocatorDump(
+    const MemoryAllocatorDumpGuid& guid) {
+  // Global dumps are disabled in background mode.
+  if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND)
+    return GetBlackHoleMad();
+
+  MemoryAllocatorDump* mad = GetSharedGlobalAllocatorDump(guid);
+  if (mad)
+    return mad;
+  mad = CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid);
+  mad->set_flags(MemoryAllocatorDump::Flags::WEAK);
+  return mad;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
+    const MemoryAllocatorDumpGuid& guid) const {
+  return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid));
+}
+
+void ProcessMemoryDump::DumpHeapUsage(
+    const base::hash_map<base::trace_event::AllocationContext,
+        base::trace_event::AllocationMetrics>& metrics_by_context,
+    base::trace_event::TraceEventMemoryOverhead& overhead,
+    const char* allocator_name) {
+  if (!metrics_by_context.empty()) {
+    DCHECK_EQ(0ul, heap_dumps_.count(allocator_name));
+    std::unique_ptr<TracedValue> heap_dump = ExportHeapDump(
+        metrics_by_context, *session_state());
+    heap_dumps_[allocator_name] = std::move(heap_dump);
+  }
+
+  std::string base_name = base::StringPrintf("tracing/heap_profiler_%s",
+                                             allocator_name);
+  overhead.DumpInto(base_name.c_str(), this);
+}
+
+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_.clear();
+  allocator_dumps_edges_.clear();
+  heap_dumps_.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, checking for duplicates.
+  for (auto& it : other->allocator_dumps_)
+    AddAllocatorDumpInternal(std::move(it.second));
+  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();
+
+  for (auto& it : other->heap_dumps_) {
+    DCHECK_EQ(0ul, heap_dumps_.count(it.first));
+    heap_dumps_.insert(std::make_pair(it.first, std::move(it.second)));
+  }
+  other->heap_dumps_.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_.size() > 0) {
+    value->BeginDictionary("allocators");
+    for (const auto& allocator_dump_it : allocator_dumps_)
+      allocator_dump_it.second->AsValueInto(value);
+    value->EndDictionary();
+  }
+
+  if (heap_dumps_.size() > 0) {
+    value->BeginDictionary("heaps");
+    for (const auto& name_and_dump : heap_dumps_)
+      value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second);
+    value->EndDictionary();  // "heaps"
+  }
+
+  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) {
+  // Do not create new dumps for suballocations in background mode.
+  if (dump_args_.level_of_detail == MemoryDumpLevelOfDetail::BACKGROUND)
+    return;
+
+  std::string child_mad_name = target_node_name + "/__" + source.ToString();
+  MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name);
+  AddOwnershipEdge(source, target_child_mad->guid());
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetBlackHoleMad() {
+  DCHECK(is_black_hole_non_fatal_for_testing_);
+  if (!black_hole_mad_)
+    black_hole_mad_.reset(new MemoryAllocatorDump("discarded", this));
+  return black_hole_mad_.get();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/process_memory_dump.h b/libchrome/base/trace_event/process_memory_dump.h
new file mode 100644
index 0000000..d020c7d
--- /dev/null
+++ b/libchrome/base/trace_event/process_memory_dump.h
@@ -0,0 +1,223 @@
+// 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 <stddef.h>
+
+#include <unordered_map>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.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_request_args.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"
+#include "build/build_config.h"
+
+// Define COUNT_RESIDENT_BYTES_SUPPORTED if platform supports counting of the
+// resident memory.
+#if (defined(OS_POSIX) && !defined(OS_NACL)) || defined(OS_WIN)
+#define COUNT_RESIDENT_BYTES_SUPPORTED
+#endif
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpManager;
+class MemoryDumpSessionState;
+class TracedValue;
+
+// ProcessMemoryDump is as a strongly typed container which holds the dumps
+// produced by the MemoryDumpProvider(s) for a specific process.
+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 =
+      std::unordered_map<std::string, std::unique_ptr<MemoryAllocatorDump>>;
+
+  using HeapDumpsMap =
+      std::unordered_map<std::string, std::unique_ptr<TracedValue>>;
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+  // Returns the number of bytes in a kernel memory page. Some platforms may
+  // have a different value for kernel page sizes from user page sizes. It is
+  // important to use kernel memory page sizes for resident bytes calculation.
+  // In most cases, the two are the same.
+  static size_t GetSystemPageSize();
+
+  // Returns the total bytes resident for a virtual address range, with given
+  // |start_address| and |mapped_size|. |mapped_size| is specified in bytes. The
+  // value returned is valid only if the given range is currently mmapped by the
+  // process. The |start_address| must be page-aligned.
+  static size_t CountResidentBytes(void* start_address, size_t mapped_size);
+#endif
+
+  ProcessMemoryDump(scoped_refptr<MemoryDumpSessionState> session_state,
+                    const MemoryDumpArgs& dump_args);
+  ~ProcessMemoryDump();
+
+  // 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() to express memory sharing. 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;
+
+  MemoryAllocatorDump* GetOrCreateAllocatorDump(
+      const std::string& absolute_name);
+
+  // 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);
+
+  // Creates a shared MemoryAllocatorDump as CreateSharedGlobalAllocatorDump,
+  // but with a WEAK flag. A weak dump will be discarded unless a non-weak dump
+  // is created using CreateSharedGlobalAllocatorDump by at least one process.
+  // The WEAK flag does not apply if a non-weak dump with the same GUID already
+  // exists or is created later. All owners and children of the discarded dump
+  // will also be discarded transitively.
+  MemoryAllocatorDump* CreateWeakSharedGlobalAllocatorDump(
+      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_; }
+
+  // Dumps heap usage with |allocator_name|.
+  void DumpHeapUsage(const base::hash_map<base::trace_event::AllocationContext,
+                                          base::trace_event::AllocationMetrics>&
+                         metrics_by_context,
+                     base::trace_event::TraceEventMemoryOverhead& overhead,
+                     const char* allocator_name);
+
+  // 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_;
+  }
+
+  // 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);
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  ProcessMemoryTotals* process_totals() { return &process_totals_; }
+  bool has_process_totals() const { return has_process_totals_; }
+  void set_has_process_totals() { has_process_totals_ = true; }
+
+  ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+  bool has_process_mmaps() const { return has_process_mmaps_; }
+  void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
+  const HeapDumpsMap& heap_dumps() const { return heap_dumps_; }
+
+  const MemoryDumpArgs& dump_args() const { return dump_args_; }
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryDumpTest, BackgroundModeTest);
+
+  MemoryAllocatorDump* AddAllocatorDumpInternal(
+      std::unique_ptr<MemoryAllocatorDump> mad);
+
+  MemoryAllocatorDump* GetBlackHoleMad();
+
+  ProcessMemoryTotals process_totals_;
+  bool has_process_totals_;
+
+  ProcessMemoryMaps process_mmaps_;
+  bool has_process_mmaps_;
+
+  AllocatorDumpsMap allocator_dumps_;
+  HeapDumpsMap heap_dumps_;
+
+  // 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_;
+
+  // Level of detail of the current dump.
+  const MemoryDumpArgs dump_args_;
+
+  // This allocator dump is returned when an invalid dump is created in
+  // background mode. The attributes of the dump are ignored and not added to
+  // the trace.
+  std::unique_ptr<MemoryAllocatorDump> black_hole_mad_;
+
+  // When set to true, the DCHECK(s) for invalid dump creations on the
+  // background mode are disabled for testing.
+  static bool is_black_hole_non_fatal_for_testing_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
diff --git a/libchrome/base/trace_event/process_memory_dump_unittest.cc b/libchrome/base/trace_event/process_memory_dump_unittest.cc
new file mode 100644
index 0000000..571774a
--- /dev/null
+++ b/libchrome/base/trace_event/process_memory_dump_unittest.cc
@@ -0,0 +1,306 @@
+// 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 <stddef.h>
+
+#include "base/memory/aligned_memory.h"
+#include "base/memory/ptr_util.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/trace_event/memory_infra_background_whitelist.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+const MemoryDumpArgs kDetailedDumpArgs = {MemoryDumpLevelOfDetail::DETAILED};
+const char* const kTestDumpNameWhitelist[] = {
+    "Whitelisted/TestName", "Whitelisted/TestName_0x?",
+    "Whitelisted/0x?/TestName", nullptr};
+
+TracedValue* GetHeapDump(const ProcessMemoryDump& pmd, const char* name) {
+  auto it = pmd.heap_dumps().find(name);
+  return it == pmd.heap_dumps().end() ? nullptr : it->second.get();
+}
+
+}  // namespace
+
+TEST(ProcessMemoryDumpTest, Clear) {
+  std::unique_ptr<ProcessMemoryDump> pmd1(
+      new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
+  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_guid1(1);
+  MemoryAllocatorDumpGuid shared_mad_guid2(2);
+  pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid1);
+  pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid2);
+
+  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_guid1));
+  ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2));
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  std::unique_ptr<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_mad1 = pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid1);
+  auto* shared_mad2 =
+      pmd1->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid2);
+  ASSERT_EQ(4u, 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_mad1, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1));
+  ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags());
+  ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2));
+  ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad2->flags());
+
+  traced_value.reset(new TracedValue);
+  pmd1->AsValueInto(traced_value.get());
+
+  pmd1.reset();
+}
+
+TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) {
+  std::unique_ptr<TracedValue> traced_value(new TracedValue);
+  hash_map<AllocationContext, AllocationMetrics> metrics_by_context;
+  metrics_by_context[AllocationContext()] = { 1, 1 };
+  TraceEventMemoryOverhead overhead;
+
+  scoped_refptr<MemoryDumpSessionState> session_state =
+      new MemoryDumpSessionState;
+  session_state->SetStackFrameDeduplicator(
+      WrapUnique(new StackFrameDeduplicator));
+  session_state->SetTypeNameDeduplicator(
+      WrapUnique(new TypeNameDeduplicator));
+  std::unique_ptr<ProcessMemoryDump> pmd1(
+      new ProcessMemoryDump(session_state.get(), kDetailedDumpArgs));
+  auto* mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1");
+  auto* mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2");
+  pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid());
+  pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump1");
+  pmd1->DumpHeapUsage(metrics_by_context, overhead, "pmd1/heap_dump2");
+
+  std::unique_ptr<ProcessMemoryDump> pmd2(
+      new ProcessMemoryDump(session_state.get(), kDetailedDumpArgs));
+  auto* mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1");
+  auto* mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2");
+  pmd2->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid());
+  pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump1");
+  pmd2->DumpHeapUsage(metrics_by_context, overhead, "pmd2/heap_dump2");
+
+  MemoryAllocatorDumpGuid shared_mad_guid1(1);
+  MemoryAllocatorDumpGuid shared_mad_guid2(2);
+  auto* shared_mad1 = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid1);
+  auto* shared_mad2 =
+      pmd2->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid2);
+
+  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());
+  ASSERT_TRUE(pmd2->heap_dumps().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(6u, 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_mad1, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid1));
+  ASSERT_EQ(shared_mad2, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid2));
+  ASSERT_TRUE(MemoryAllocatorDump::Flags::WEAK & shared_mad2->flags());
+  ASSERT_EQ(4u, pmd1->heap_dumps().size());
+  ASSERT_TRUE(GetHeapDump(*pmd1, "pmd1/heap_dump1") != nullptr);
+  ASSERT_TRUE(GetHeapDump(*pmd1, "pmd1/heap_dump2") != nullptr);
+  ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump1") != nullptr);
+  ASSERT_TRUE(GetHeapDump(*pmd1, "pmd2/heap_dump2") != nullptr);
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  traced_value.reset(new TracedValue);
+  pmd1->AsValueInto(traced_value.get());
+
+  pmd1.reset();
+}
+
+TEST(ProcessMemoryDumpTest, Suballocations) {
+  std::unique_ptr<ProcessMemoryDump> pmd(
+      new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
+  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.
+  std::unique_ptr<TracedValue> traced_value(new TracedValue);
+  pmd->AsValueInto(traced_value.get());
+
+  pmd.reset();
+}
+
+TEST(ProcessMemoryDumpTest, GlobalAllocatorDumpTest) {
+  std::unique_ptr<ProcessMemoryDump> pmd(
+      new ProcessMemoryDump(nullptr, kDetailedDumpArgs));
+  MemoryAllocatorDumpGuid shared_mad_guid(1);
+  auto* shared_mad1 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid);
+  ASSERT_EQ(shared_mad_guid, shared_mad1->guid());
+  ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags());
+
+  auto* shared_mad2 = pmd->GetSharedGlobalAllocatorDump(shared_mad_guid);
+  ASSERT_EQ(shared_mad1, shared_mad2);
+  ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags());
+
+  auto* shared_mad3 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid);
+  ASSERT_EQ(shared_mad1, shared_mad3);
+  ASSERT_EQ(MemoryAllocatorDump::Flags::WEAK, shared_mad1->flags());
+
+  auto* shared_mad4 = pmd->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+  ASSERT_EQ(shared_mad1, shared_mad4);
+  ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags());
+
+  auto* shared_mad5 = pmd->CreateWeakSharedGlobalAllocatorDump(shared_mad_guid);
+  ASSERT_EQ(shared_mad1, shared_mad5);
+  ASSERT_EQ(MemoryAllocatorDump::Flags::DEFAULT, shared_mad1->flags());
+}
+
+TEST(ProcessMemoryDumpTest, BackgroundModeTest) {
+  MemoryDumpArgs background_args = {MemoryDumpLevelOfDetail::BACKGROUND};
+  std::unique_ptr<ProcessMemoryDump> pmd(
+      new ProcessMemoryDump(nullptr, background_args));
+  ProcessMemoryDump::is_black_hole_non_fatal_for_testing_ = true;
+  SetAllocatorDumpNameWhitelistForTesting(kTestDumpNameWhitelist);
+  MemoryAllocatorDump* black_hole_mad = pmd->GetBlackHoleMad();
+
+  // Invalid dump names.
+  EXPECT_EQ(black_hole_mad,
+            pmd->CreateAllocatorDump("NotWhitelisted/TestName"));
+  EXPECT_EQ(black_hole_mad, pmd->CreateAllocatorDump("TestName"));
+  EXPECT_EQ(black_hole_mad, pmd->CreateAllocatorDump("Whitelisted/Test"));
+  EXPECT_EQ(black_hole_mad,
+            pmd->CreateAllocatorDump("Not/Whitelisted/TestName"));
+  EXPECT_EQ(black_hole_mad,
+            pmd->CreateAllocatorDump("Whitelisted/TestName/Google"));
+  EXPECT_EQ(black_hole_mad,
+            pmd->CreateAllocatorDump("Whitelisted/TestName/0x1a2Google"));
+  EXPECT_EQ(black_hole_mad,
+            pmd->CreateAllocatorDump("Whitelisted/TestName/__12/Google"));
+
+  // Global dumps.
+  MemoryAllocatorDumpGuid guid(1);
+  EXPECT_EQ(black_hole_mad, pmd->CreateSharedGlobalAllocatorDump(guid));
+  EXPECT_EQ(black_hole_mad, pmd->CreateWeakSharedGlobalAllocatorDump(guid));
+  EXPECT_EQ(black_hole_mad, pmd->GetSharedGlobalAllocatorDump(guid));
+
+  // Suballocations.
+  pmd->AddSuballocation(guid, "malloc/allocated_objects");
+  EXPECT_EQ(0u, pmd->allocator_dumps_edges_.size());
+  EXPECT_EQ(0u, pmd->allocator_dumps_.size());
+
+  // Valid dump names.
+  EXPECT_NE(black_hole_mad, pmd->CreateAllocatorDump("Whitelisted/TestName"));
+  EXPECT_NE(black_hole_mad,
+            pmd->CreateAllocatorDump("Whitelisted/TestName_0xA1b2"));
+  EXPECT_NE(black_hole_mad,
+            pmd->CreateAllocatorDump("Whitelisted/0xaB/TestName"));
+
+  // GetAllocatorDump is consistent.
+  EXPECT_EQ(black_hole_mad, pmd->GetAllocatorDump("NotWhitelisted/TestName"));
+  EXPECT_NE(black_hole_mad, pmd->GetAllocatorDump("Whitelisted/TestName"));
+}
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+TEST(ProcessMemoryDumpTest, CountResidentBytes) {
+  const size_t page_size = ProcessMemoryDump::GetSystemPageSize();
+
+  // Allocate few page of dirty memory and check if it is resident.
+  const size_t size1 = 5 * page_size;
+  std::unique_ptr<char, base::AlignedFreeDeleter> memory1(
+      static_cast<char*>(base::AlignedAlloc(size1, page_size)));
+  memset(memory1.get(), 0, size1);
+  size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1);
+  ASSERT_EQ(res1, size1);
+
+  // Allocate a large memory segment (> 8Mib).
+  const size_t kVeryLargeMemorySize = 15 * 1024 * 1024;
+  std::unique_ptr<char, base::AlignedFreeDeleter> memory2(
+      static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size)));
+  memset(memory2.get(), 0, kVeryLargeMemorySize);
+  size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(),
+                                                      kVeryLargeMemorySize);
+  ASSERT_EQ(res2, kVeryLargeMemorySize);
+}
+#endif  // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/process_memory_maps.cc b/libchrome/base/trace_event/process_memory_maps.cc
new file mode 100644
index 0000000..a121239
--- /dev/null
+++ b/libchrome/base/trace_event/process_memory_maps.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/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_t ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsMayshare = 128;
+
+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::VMRegion::VMRegion(const VMRegion& other) = default;
+
+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/libchrome/base/trace_event/process_memory_maps.h b/libchrome/base/trace_event/process_memory_maps.h
new file mode 100644
index 0000000..6a73674
--- /dev/null
+++ b/libchrome/base/trace_event/process_memory_maps.h
@@ -0,0 +1,72 @@
+// 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 <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.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_t kProtectionFlagsRead;
+    static const uint32_t kProtectionFlagsWrite;
+    static const uint32_t kProtectionFlagsExec;
+    static const uint32_t kProtectionFlagsMayshare;
+
+    VMRegion();
+    VMRegion(const VMRegion& other);
+
+    uint64_t start_address;
+    uint64_t size_in_bytes;
+    uint32_t protection_flags;
+    std::string mapped_file;
+
+    // private_dirty_resident + private_clean_resident + shared_dirty_resident +
+    // shared_clean_resident = resident set size.
+    uint64_t byte_stats_private_dirty_resident;
+    uint64_t byte_stats_private_clean_resident;
+    uint64_t byte_stats_shared_dirty_resident;
+    uint64_t byte_stats_shared_clean_resident;
+
+    uint64_t byte_stats_swapped;
+
+    // For multiprocess accounting.
+    uint64_t 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/libchrome/base/trace_event/process_memory_totals.cc b/libchrome/base/trace_event/process_memory_totals.cc
new file mode 100644
index 0000000..de27ab3
--- /dev/null
+++ b/libchrome/base/trace_event/process_memory_totals.cc
@@ -0,0 +1,47 @@
+// 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) {
+}
+
+ProcessMemoryTotals::~ProcessMemoryTotals() {}
+
+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_);
+  }
+
+  for (const auto it : extra_fields_) {
+    value->SetString(it.first, StringPrintf("%" PRIx64, it.second));
+  }
+}
+
+void ProcessMemoryTotals::Clear() {
+  resident_set_bytes_ = 0;
+}
+
+void ProcessMemoryTotals::SetExtraFieldInBytes(const char* name,
+                                               uint64_t value) {
+  DCHECK_EQ(0u, extra_fields_.count(name));
+  extra_fields_[name] = value;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/process_memory_totals.h b/libchrome/base/trace_event/process_memory_totals.h
new file mode 100644
index 0000000..329967a
--- /dev/null
+++ b/libchrome/base/trace_event/process_memory_totals.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_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+
+#include <stdint.h>
+
+#include <map>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotals {
+ public:
+  ProcessMemoryTotals();
+  ~ProcessMemoryTotals();
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  // Clears up all the data collected.
+  void Clear();
+
+  uint64_t resident_set_bytes() const { return resident_set_bytes_; }
+  void set_resident_set_bytes(uint64_t value) { resident_set_bytes_ = value; }
+
+  uint64_t peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
+  void set_peak_resident_set_bytes(uint64_t 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; }
+
+  void SetExtraFieldInBytes(const char* name, uint64_t value);
+
+ private:
+  uint64_t resident_set_bytes_;
+  uint64_t peak_resident_set_bytes_;
+  bool is_peak_rss_resetable_;
+
+  // Extra metrics for OS-specific statistics.
+  std::map<const char*, uint64_t> extra_fields_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
diff --git a/libchrome/base/trace_event/trace_buffer.cc b/libchrome/base/trace_event/trace_buffer.cc
new file mode 100644
index 0000000..d40f430
--- /dev/null
+++ b/libchrome/base/trace_event/trace_buffer.cc
@@ -0,0 +1,344 @@
+// 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_buffer.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+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;
+  }
+
+  std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+    HEAP_PROFILER_SCOPED_IGNORE;
+
+    // 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].release();
+    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 std::unique_ptr<TraceBufferChunk>(chunk);
+  }
+
+  void ReturnChunk(size_t index,
+                   std::unique_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] = std::move(chunk);
+    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() * TraceBufferChunk::kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * TraceBufferChunk::kTraceBufferChunkSize;
+  }
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+    if (handle.chunk_index >= chunks_.size())
+      return NULL;
+    TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
+    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].get();
+    }
+    return NULL;
+  }
+
+  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:
+  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_;
+  std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
+
+  std::unique_ptr<size_t[]> recyclable_chunks_queue_;
+  size_t queue_head_;
+  size_t queue_tail_;
+
+  size_t current_iteration_index_;
+  uint32_t 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_);
+  }
+
+  std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+    HEAP_PROFILER_SCOPED_IGNORE;
+
+    // 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 std::unique_ptr<TraceBufferChunk>(
+        new TraceBufferChunk(static_cast<uint32_t>(*index) + 1));
+  }
+
+  void ReturnChunk(size_t index,
+                   std::unique_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() * TraceBufferChunk::kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * TraceBufferChunk::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;
+  }
+
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    const size_t chunks_ptr_vector_allocated_size =
+        sizeof(*this) + max_chunks_ * sizeof(decltype(chunks_)::value_type);
+    const size_t chunks_ptr_vector_resident_size =
+        sizeof(*this) + chunks_.size() * sizeof(decltype(chunks_)::value_type);
+    overhead->Add("TraceBufferVector", chunks_ptr_vector_allocated_size,
+                  chunks_ptr_vector_resident_size);
+    for (size_t i = 0; i < chunks_.size(); ++i) {
+      TraceBufferChunk* chunk = chunks_[i];
+      // Skip the in-flight (nullptr) chunks. They will be accounted by the
+      // per-thread-local dumpers, see ThreadLocalEventBuffer::OnMemoryDump.
+      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);
+};
+
+}  // namespace
+
+TraceBufferChunk::TraceBufferChunk(uint32_t seq) : next_free_(0), seq_(seq) {}
+
+TraceBufferChunk::~TraceBufferChunk() {}
+
+void TraceBufferChunk::Reset(uint32_t new_seq) {
+  for (size_t i = 0; i < next_free_; ++i)
+    chunk_[i].Reset();
+  next_free_ = 0;
+  seq_ = new_seq;
+  cached_overhead_estimate_.reset();
+}
+
+TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
+  DCHECK(!IsFull());
+  *event_index = next_free_++;
+  return &chunk_[*event_index];
+}
+
+void TraceBufferChunk::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (!cached_overhead_estimate_) {
+    cached_overhead_estimate_.reset(new TraceEventMemoryOverhead);
+
+    // When estimating the size of TraceBufferChunk, exclude the array of trace
+    // events, as they are computed individually below.
+    cached_overhead_estimate_->Add("TraceBufferChunk",
+                                   sizeof(*this) - sizeof(chunk_));
+  }
+
+  const size_t num_cached_estimated_events =
+      cached_overhead_estimate_->GetCount("TraceEvent");
+  DCHECK_LE(num_cached_estimated_events, size());
+
+  if (IsFull() && num_cached_estimated_events == size()) {
+    overhead->Update(*cached_overhead_estimate_);
+    return;
+  }
+
+  for (size_t i = num_cached_estimated_events; i < size(); ++i)
+    chunk_[i].EstimateTraceMemoryOverhead(cached_overhead_estimate_.get());
+
+  if (IsFull()) {
+    cached_overhead_estimate_->AddSelf();
+  } else {
+    // The unused TraceEvents in |chunks_| are not cached. They will keep
+    // changing as new TraceEvents are added to this chunk, so they are
+    // computed on the fly.
+    const size_t num_unused_trace_events = capacity() - size();
+    overhead->Add("TraceEvent (unused)",
+                  num_unused_trace_events * sizeof(TraceEvent));
+  }
+
+  overhead->Update(*cached_overhead_estimate_);
+}
+
+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("]");
+}
+
+TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer(size_t max_chunks) {
+  return new TraceBufferRingBuffer(max_chunks);
+}
+
+TraceBuffer* TraceBuffer::CreateTraceBufferVectorOfSize(size_t max_chunks) {
+  return new TraceBufferVector(max_chunks);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_buffer.h b/libchrome/base/trace_event/trace_buffer.h
new file mode 100644
index 0000000..4885a3c
--- /dev/null
+++ b/libchrome/base/trace_event/trace_buffer.h
@@ -0,0 +1,130 @@
+// 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_BUFFER_H_
+#define BASE_TRACE_EVENT_TRACE_BUFFER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+
+namespace trace_event {
+
+// TraceBufferChunk is the basic unit of TraceBuffer.
+class BASE_EXPORT TraceBufferChunk {
+ public:
+  explicit TraceBufferChunk(uint32_t seq);
+  ~TraceBufferChunk();
+
+  void Reset(uint32_t new_seq);
+  TraceEvent* AddTraceEvent(size_t* event_index);
+  bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
+
+  uint32_t 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];
+  }
+
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  // These values must be kept consistent with the numbers of bits of
+  // chunk_index and event_index fields in TraceEventHandle
+  // (in trace_event_impl.h).
+  static const size_t kMaxChunkIndex = (1u << 26) - 1;
+  static const size_t kTraceBufferChunkSize = 64;
+
+ private:
+  size_t next_free_;
+  std::unique_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_;
+  TraceEvent chunk_[kTraceBufferChunkSize];
+  uint32_t seq_;
+};
+
+// TraceBuffer holds the events as they are collected.
+class BASE_EXPORT TraceBuffer {
+ public:
+  virtual ~TraceBuffer() {}
+
+  virtual std::unique_ptr<TraceBufferChunk> GetChunk(size_t* index) = 0;
+  virtual void ReturnChunk(size_t index,
+                           std::unique_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;
+
+
+  // Computes an estimate of the size of the buffer, including all the retained
+  // objects.
+  virtual void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) = 0;
+
+  static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks);
+  static TraceBuffer* CreateTraceBufferVectorOfSize(size_t max_chunks);
+};
+
+// 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_;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_BUFFER_H_
diff --git a/libchrome/base/trace_event/trace_config.cc b/libchrome/base/trace_event/trace_config.cc
new file mode 100644
index 0000000..b343ea0
--- /dev/null
+++ b/libchrome/base/trace_event/trace_config.cc
@@ -0,0 +1,706 @@
+// 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 <stddef.h>
+
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/pattern.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/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.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(";
+
+// String parameters that is used to parse memory dump config in trace config
+// string.
+const char kMemoryDumpConfigParam[] = "memory_dump_config";
+const char kAllowedDumpModesParam[] = "allowed_dump_modes";
+const char kTriggersParam[] = "triggers";
+const char kPeriodicIntervalParam[] = "periodic_interval_ms";
+const char kModeParam[] = "mode";
+const char kHeapProfilerOptions[] = "heap_profiler_options";
+const char kBreakdownThresholdBytes[] = "breakdown_threshold_bytes";
+
+// Default configuration of memory dumps.
+const TraceConfig::MemoryDumpConfig::Trigger kDefaultHeavyMemoryDumpTrigger = {
+    2000,  // periodic_interval_ms
+    MemoryDumpLevelOfDetail::DETAILED};
+const TraceConfig::MemoryDumpConfig::Trigger kDefaultLightMemoryDumpTrigger = {
+    250,  // periodic_interval_ms
+    MemoryDumpLevelOfDetail::LIGHT};
+
+class ConvertableTraceConfigToTraceFormat
+    : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
+      : trace_config_(trace_config) {}
+  ~ConvertableTraceConfigToTraceFormat() override {}
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append(trace_config_.ToString());
+  }
+
+ private:
+  const TraceConfig trace_config_;
+};
+
+std::set<MemoryDumpLevelOfDetail> GetDefaultAllowedMemoryDumpModes() {
+  std::set<MemoryDumpLevelOfDetail> all_modes;
+  for (uint32_t mode = static_cast<uint32_t>(MemoryDumpLevelOfDetail::FIRST);
+       mode <= static_cast<uint32_t>(MemoryDumpLevelOfDetail::LAST); mode++) {
+    all_modes.insert(static_cast<MemoryDumpLevelOfDetail>(mode));
+  }
+  return all_modes;
+}
+
+}  // namespace
+
+TraceConfig::MemoryDumpConfig::HeapProfiler::HeapProfiler()
+    : breakdown_threshold_bytes(kDefaultBreakdownThresholdBytes) {}
+
+void TraceConfig::MemoryDumpConfig::HeapProfiler::Clear() {
+  breakdown_threshold_bytes = kDefaultBreakdownThresholdBytes;
+}
+
+void TraceConfig::ResetMemoryDumpConfig(
+    const TraceConfig::MemoryDumpConfig& memory_dump_config) {
+  memory_dump_config_.Clear();
+  memory_dump_config_ = memory_dump_config;
+}
+
+TraceConfig::MemoryDumpConfig::MemoryDumpConfig() {}
+
+TraceConfig::MemoryDumpConfig::MemoryDumpConfig(
+    const MemoryDumpConfig& other) = default;
+
+TraceConfig::MemoryDumpConfig::~MemoryDumpConfig() {}
+
+void TraceConfig::MemoryDumpConfig::Clear() {
+  allowed_dump_modes.clear();
+  triggers.clear();
+  heap_profiler_options.Clear();
+}
+
+TraceConfig::TraceConfig() {
+  InitializeDefault();
+}
+
+TraceConfig::TraceConfig(StringPiece category_filter_string,
+                         StringPiece trace_options_string) {
+  InitializeFromStrings(category_filter_string, trace_options_string);
+}
+
+TraceConfig::TraceConfig(StringPiece 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 DictionaryValue& config) {
+  InitializeFromConfigDict(config);
+}
+
+TraceConfig::TraceConfig(StringPiece 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_),
+      memory_dump_config_(tc.memory_dump_config_),
+      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_;
+  memory_dump_config_ = rhs.memory_dump_config_;
+  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 {
+  std::unique_ptr<DictionaryValue> dict = ToDict();
+  std::string json;
+  JSONWriter::Write(*dict, &json);
+  return json;
+}
+
+std::unique_ptr<ConvertableToTraceFormat>
+TraceConfig::AsConvertableToTraceFormat() const {
+  return WrapUnique(new ConvertableTraceConfigToTraceFormat(*this));
+}
+
+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);
+  std::string category_group_name_str = category_group_name;
+  StringTokenizer category_group_tokens(category_group_name_str, ",");
+  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, 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 (const std::string& category : excluded_categories_) {
+      if (MatchPattern(category_group_token, category)) {
+        // 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, if it's not a disabled-by-default category,
+      // it has to be included_ list. Enable the category_group_name
+      // for recording.
+      if (!MatchPattern(category_group_token, TRACE_DISABLED_BY_DEFAULT("*"))) {
+        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 && had_enabled_by_default &&
+         included_categories_.empty();
+}
+
+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();
+  }
+
+  memory_dump_config_.triggers.insert(memory_dump_config_.triggers.end(),
+                             config.memory_dump_config_.triggers.begin(),
+                             config.memory_dump_config_.triggers.end());
+
+  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();
+  memory_dump_config_.Clear();
+}
+
+void TraceConfig::InitializeDefault() {
+  record_mode_ = RECORD_UNTIL_FULL;
+  enable_sampling_ = false;
+  enable_systrace_ = false;
+  enable_argument_filter_ = false;
+}
+
+void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
+  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 val;
+  enable_sampling_ = dict.GetBoolean(kEnableSamplingParam, &val) ? val : false;
+  enable_systrace_ = dict.GetBoolean(kEnableSystraceParam, &val) ? val : false;
+  enable_argument_filter_ =
+      dict.GetBoolean(kEnableArgumentFilterParam, &val) ? val : false;
+
+  const ListValue* category_list = nullptr;
+  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);
+
+  if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+    // If dump triggers not set, the client is using the legacy with just
+    // category enabled. So, use the default periodic dump config.
+    const DictionaryValue* memory_dump_config = nullptr;
+    if (dict.GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
+      SetMemoryDumpConfigFromConfigDict(*memory_dump_config);
+    else
+      SetDefaultMemoryDumpConfig();
+  }
+}
+
+void TraceConfig::InitializeFromConfigString(StringPiece config_string) {
+  auto dict = DictionaryValue::From(JSONReader::Read(config_string));
+  if (dict)
+    InitializeFromConfigDict(*dict);
+  else
+    InitializeDefault();
+}
+
+void TraceConfig::InitializeFromStrings(StringPiece category_filter_string,
+                                        StringPiece trace_options_string) {
+  if (!category_filter_string.empty()) {
+    std::vector<std::string> split = SplitString(
+        category_filter_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+    for (const std::string& category : split) {
+      // Ignore empty categories.
+      if (category.empty())
+        continue;
+      // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
+      if (StartsWith(category, kSyntheticDelayCategoryFilterPrefix,
+                     CompareCase::SENSITIVE) &&
+          category.back() == ')') {
+        std::string synthetic_category = category.substr(
+            strlen(kSyntheticDelayCategoryFilterPrefix),
+            category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1);
+        size_t name_length = synthetic_category.find(';');
+        if (name_length != std::string::npos && name_length > 0 &&
+            name_length != synthetic_category.size() - 1) {
+          synthetic_delays_.push_back(synthetic_category);
+        }
+      } else if (category.front() == '-') {
+        // Excluded categories start with '-'.
+        // Remove '-' from category string.
+        excluded_categories_.push_back(category.substr(1));
+      } 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 =
+        SplitString(trace_options_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+    for (const std::string& token : split) {
+      if (token == kRecordUntilFull) {
+        record_mode_ = RECORD_UNTIL_FULL;
+      } else if (token == kRecordContinuously) {
+        record_mode_ = RECORD_CONTINUOUSLY;
+      } else if (token == kTraceToConsole) {
+        record_mode_ = ECHO_TO_CONSOLE;
+      } else if (token == kRecordAsMuchAsPossible) {
+        record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
+      } else if (token == kEnableSampling) {
+        enable_sampling_ = true;
+      } else if (token == kEnableSystrace) {
+        enable_systrace_ = true;
+      } else if (token == kEnableArgumentFilter) {
+        enable_argument_filter_ = true;
+      }
+    }
+  }
+
+  if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+    SetDefaultMemoryDumpConfig();
+  }
+}
+
+void TraceConfig::SetCategoriesFromIncludedList(
+    const 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 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 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(DictionaryValue* dict,
+                                    const char* param,
+                                    const StringList& categories) const {
+  if (categories.empty())
+    return;
+
+  auto list = MakeUnique<ListValue>();
+  for (const std::string& category : categories)
+    list->AppendString(category);
+  dict->Set(param, std::move(list));
+}
+
+void TraceConfig::SetMemoryDumpConfigFromConfigDict(
+    const DictionaryValue& memory_dump_config) {
+  // Set allowed dump modes.
+  memory_dump_config_.allowed_dump_modes.clear();
+  const ListValue* allowed_modes_list;
+  if (memory_dump_config.GetList(kAllowedDumpModesParam, &allowed_modes_list)) {
+    for (size_t i = 0; i < allowed_modes_list->GetSize(); ++i) {
+      std::string level_of_detail_str;
+      allowed_modes_list->GetString(i, &level_of_detail_str);
+      memory_dump_config_.allowed_dump_modes.insert(
+          StringToMemoryDumpLevelOfDetail(level_of_detail_str));
+    }
+  } else {
+    // If allowed modes param is not given then allow all modes by default.
+    memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
+  }
+
+  // Set triggers
+  memory_dump_config_.triggers.clear();
+  const ListValue* trigger_list = nullptr;
+  if (memory_dump_config.GetList(kTriggersParam, &trigger_list) &&
+      trigger_list->GetSize() > 0) {
+    for (size_t i = 0; i < trigger_list->GetSize(); ++i) {
+      const DictionaryValue* trigger = nullptr;
+      if (!trigger_list->GetDictionary(i, &trigger))
+        continue;
+
+      int interval = 0;
+      if (!trigger->GetInteger(kPeriodicIntervalParam, &interval))
+        continue;
+
+      DCHECK_GT(interval, 0);
+      MemoryDumpConfig::Trigger dump_config;
+      dump_config.periodic_interval_ms = static_cast<uint32_t>(interval);
+      std::string level_of_detail_str;
+      trigger->GetString(kModeParam, &level_of_detail_str);
+      dump_config.level_of_detail =
+          StringToMemoryDumpLevelOfDetail(level_of_detail_str);
+      memory_dump_config_.triggers.push_back(dump_config);
+    }
+  }
+
+  // Set heap profiler options
+  const DictionaryValue* heap_profiler_options = nullptr;
+  if (memory_dump_config.GetDictionary(kHeapProfilerOptions,
+                                       &heap_profiler_options)) {
+    int min_size_bytes = 0;
+    if (heap_profiler_options->GetInteger(kBreakdownThresholdBytes,
+                                         &min_size_bytes)
+        && min_size_bytes >= 0) {
+      memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
+          static_cast<size_t>(min_size_bytes);
+    } else {
+      memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes =
+          MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes;
+    }
+  }
+}
+
+void TraceConfig::SetDefaultMemoryDumpConfig() {
+  memory_dump_config_.Clear();
+  memory_dump_config_.triggers.push_back(kDefaultHeavyMemoryDumpTrigger);
+  memory_dump_config_.triggers.push_back(kDefaultLightMemoryDumpTrigger);
+  memory_dump_config_.allowed_dump_modes = GetDefaultAllowedMemoryDumpModes();
+}
+
+std::unique_ptr<DictionaryValue> TraceConfig::ToDict() const {
+  auto dict = MakeUnique<DictionaryValue>();
+  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();
+  }
+
+  dict->SetBoolean(kEnableSamplingParam, enable_sampling_);
+  dict->SetBoolean(kEnableSystraceParam, enable_systrace_);
+  dict->SetBoolean(kEnableArgumentFilterParam, enable_argument_filter_);
+
+  StringList categories(included_categories_);
+  categories.insert(categories.end(),
+                    disabled_categories_.begin(),
+                    disabled_categories_.end());
+  AddCategoryToDict(dict.get(), kIncludedCategoriesParam, categories);
+  AddCategoryToDict(dict.get(), kExcludedCategoriesParam, excluded_categories_);
+  AddCategoryToDict(dict.get(), kSyntheticDelaysParam, synthetic_delays_);
+
+  if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
+    auto allowed_modes = MakeUnique<ListValue>();
+    for (auto dump_mode : memory_dump_config_.allowed_dump_modes)
+      allowed_modes->AppendString(MemoryDumpLevelOfDetailToString(dump_mode));
+
+    auto memory_dump_config = MakeUnique<DictionaryValue>();
+    memory_dump_config->Set(kAllowedDumpModesParam, std::move(allowed_modes));
+
+    auto triggers_list = MakeUnique<ListValue>();
+    for (const auto& config : memory_dump_config_.triggers) {
+      auto trigger_dict = MakeUnique<DictionaryValue>();
+      trigger_dict->SetInteger(kPeriodicIntervalParam,
+                               static_cast<int>(config.periodic_interval_ms));
+      trigger_dict->SetString(
+          kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
+      triggers_list->Append(std::move(trigger_dict));
+    }
+
+    // Empty triggers will still be specified explicitly since it means that
+    // the periodic dumps are not enabled.
+    memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
+
+    if (memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes !=
+        MemoryDumpConfig::HeapProfiler::kDefaultBreakdownThresholdBytes) {
+      auto options = MakeUnique<DictionaryValue>();
+      options->SetInteger(
+          kBreakdownThresholdBytes,
+          memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
+      memory_dump_config->Set(kHeapProfilerOptions, std::move(options));
+    }
+    dict->Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
+  }
+  return dict;
+}
+
+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 (const std::string& category : values) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s", (included ? "" : "-"), category.c_str());
+    ++token_cnt;
+  }
+}
+
+void TraceConfig::WriteCategoryFilterString(const StringList& delays,
+                                            std::string* out) const {
+  bool prepend_comma = !out->empty();
+  int token_cnt = 0;
+  for (const std::string& category : delays) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix,
+                  category.c_str());
+    ++token_cnt;
+  }
+}
+
+bool TraceConfig::IsCategoryEnabled(const char* category_name) const {
+  // Check the disabled- filters and the disabled-* wildcard first so that a
+  // "*" filter does not include the disabled.
+  for (const std::string& category : disabled_categories_) {
+    if (MatchPattern(category_name, category))
+      return true;
+  }
+
+  if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
+    return false;
+
+  for (const std::string& category : included_categories_) {
+    if (MatchPattern(category_name, category))
+      return true;
+  }
+
+  return false;
+}
+
+bool TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+    StringPiece str) {
+  return str.empty() || str.front() == ' ' || str.back() == ' ';
+}
+
+bool TraceConfig::HasIncludedPatterns() const {
+  return !included_categories_.empty();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_config.h b/libchrome/base/trace_event/trace_config.h
new file mode 100644
index 0000000..91d6f1f
--- /dev/null
+++ b/libchrome/base/trace_event/trace_config.h
@@ -0,0 +1,289 @@
+// 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_CONFIG_H_
+#define BASE_TRACE_EVENT_TRACE_CONFIG_H_
+
+#include <stdint.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/strings/string_piece.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+class ConvertableToTraceFormat;
+
+// 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:
+  using StringList = std::vector<std::string>;
+
+  // Specifies the memory dump config for tracing.
+  // Used only when "memory-infra" category is enabled.
+  struct BASE_EXPORT MemoryDumpConfig {
+    MemoryDumpConfig();
+    MemoryDumpConfig(const MemoryDumpConfig& other);
+    ~MemoryDumpConfig();
+
+    // Specifies the triggers in the memory dump config.
+    struct Trigger {
+      uint32_t periodic_interval_ms;
+      MemoryDumpLevelOfDetail level_of_detail;
+    };
+
+    // Specifies the configuration options for the heap profiler.
+    struct HeapProfiler {
+      // Default value for |breakdown_threshold_bytes|.
+      enum { kDefaultBreakdownThresholdBytes = 1024 };
+
+      HeapProfiler();
+
+      // Reset the options to default.
+      void Clear();
+
+      uint32_t breakdown_threshold_bytes;
+    };
+
+    // Reset the values in the config.
+    void Clear();
+
+    // Set of memory dump modes allowed for the tracing session. The explicitly
+    // triggered dumps will be successful only if the dump mode is allowed in
+    // the config.
+    std::set<MemoryDumpLevelOfDetail> allowed_dump_modes;
+
+    std::vector<Trigger> triggers;
+    HeapProfiler heap_profiler_options;
+  };
+
+  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(StringPiece category_filter_string,
+              StringPiece trace_options_string);
+
+  TraceConfig(StringPiece 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-memory-infra"],
+  //     "excluded_categories": ["excluded", "exc_pattern*"],
+  //     "synthetic_delays": ["test.Delay1;16", "test.Delay2;32"],
+  //     "memory_dump_config": {
+  //       "triggers": [
+  //         {
+  //           "mode": "detailed",
+  //           "periodic_interval_ms": 2000
+  //         }
+  //       ]
+  //     }
+  //   }
+  //
+  // Note: memory_dump_config can be specified only if
+  // disabled-by-default-memory-infra category is enabled.
+  explicit TraceConfig(StringPiece config_string);
+
+  // Functionally identical to the above, but takes a parsed dictionary as input
+  // instead of its JSON serialization.
+  explicit TraceConfig(const DictionaryValue& config);
+
+  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;
+
+  // Returns a copy of the TraceConfig wrapped in a ConvertableToTraceFormat
+  std::unique_ptr<ConvertableToTraceFormat> AsConvertableToTraceFormat() 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. This is used to determine if the category filters are
+  // enabled in the TRACE_* macros.
+  bool IsCategoryGroupEnabled(const char* category_group) const;
+
+  // Merges config with the current TraceConfig
+  void Merge(const TraceConfig& config);
+
+  void Clear();
+
+  // Clears and resets the memory dump config.
+  void ResetMemoryDumpConfig(const MemoryDumpConfig& memory_dump_config);
+
+  const MemoryDumpConfig& memory_dump_config() const {
+    return memory_dump_config_;
+  }
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidLegacyFormat);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
+                           TraceConfigFromInvalidLegacyStrings);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromInvalidString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
+                           IsEmptyOrContainsLeadingOrTrailingWhitespace);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromMemoryConfigString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, LegacyStringToMemoryDumpConfig);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, EmptyMemoryDumpConfigTest);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
+                           EmptyAndAsteriskCategoryFilterString);
+
+  // 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 a config dictionary.
+  void InitializeFromConfigDict(const DictionaryValue& dict);
+
+  // Initialize from a config string.
+  void InitializeFromConfigString(StringPiece config_string);
+
+  // Initialize from category filter and trace options strings
+  void InitializeFromStrings(StringPiece category_filter_string,
+                             StringPiece trace_options_string);
+
+  void SetCategoriesFromIncludedList(const ListValue& included_list);
+  void SetCategoriesFromExcludedList(const ListValue& excluded_list);
+  void SetSyntheticDelaysFromList(const ListValue& list);
+  void AddCategoryToDict(DictionaryValue* dict,
+                         const char* param,
+                         const StringList& categories) const;
+
+  void SetMemoryDumpConfigFromConfigDict(
+      const DictionaryValue& memory_dump_config);
+  void SetDefaultMemoryDumpConfig();
+
+  std::unique_ptr<DictionaryValue> ToDict() 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 the category is enabled according to this trace config.
+  // This tells whether a category is enabled from the TraceConfig's
+  // perspective. Please refer to IsCategoryGroupEnabled() to determine if a
+  // category is enabled from the tracing runtime's perspective.
+  bool IsCategoryEnabled(const char* category_name) const;
+
+  static bool IsEmptyOrContainsLeadingOrTrailingWhitespace(StringPiece str);
+
+  bool HasIncludedPatterns() const;
+
+  TraceRecordMode record_mode_;
+  bool enable_sampling_ : 1;
+  bool enable_systrace_ : 1;
+  bool enable_argument_filter_ : 1;
+
+  MemoryDumpConfig memory_dump_config_;
+
+  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/libchrome/base/trace_event/trace_config_memory_test_util.h b/libchrome/base/trace_event/trace_config_memory_test_util.h
new file mode 100644
index 0000000..6b47f8d
--- /dev/null
+++ b/libchrome/base/trace_event/trace_config_memory_test_util.h
@@ -0,0 +1,103 @@
+// 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_CONFIG_MEMORY_TEST_UTIL_H_
+#define BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceConfigMemoryTestUtil {
+ public:
+  static std::string GetTraceConfig_PeriodicTriggers(int light_period,
+                                                     int heavy_period) {
+    return StringPrintf(
+        "{"
+          "\"enable_argument_filter\":false,"
+          "\"enable_sampling\":false,"
+          "\"enable_systrace\":false,"
+          "\"included_categories\":["
+            "\"%s\""
+          "],"
+          "\"memory_dump_config\":{"
+             "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
+             "\"heap_profiler_options\":{"
+               "\"breakdown_threshold_bytes\":2048"
+             "},"
+             "\"triggers\":["
+              "{"
+                "\"mode\":\"light\","
+                "\"periodic_interval_ms\":%d"
+              "},"
+              "{"
+                "\"mode\":\"detailed\","
+                "\"periodic_interval_ms\":%d"
+              "}"
+            "]"
+          "},"
+          "\"record_mode\":\"record-until-full\""
+        "}", MemoryDumpManager::kTraceCategory, light_period, heavy_period);
+  }
+
+  static std::string GetTraceConfig_EmptyTriggers() {
+    return StringPrintf(
+        "{"
+          "\"enable_argument_filter\":false,"
+          "\"enable_sampling\":false,"
+          "\"enable_systrace\":false,"
+          "\"included_categories\":["
+            "\"%s\""
+          "],"
+          "\"memory_dump_config\":{"
+            "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
+            "\"triggers\":["
+            "]"
+          "},"
+          "\"record_mode\":\"record-until-full\""
+        "}", MemoryDumpManager::kTraceCategory);
+  }
+
+  static std::string GetTraceConfig_NoTriggers() {
+    return StringPrintf(
+        "{"
+          "\"enable_argument_filter\":false,"
+          "\"enable_sampling\":false,"
+          "\"enable_systrace\":false,"
+          "\"included_categories\":["
+            "\"%s\""
+          "],"
+          "\"record_mode\":\"record-until-full\""
+        "}", MemoryDumpManager::kTraceCategory);
+  }
+
+  static std::string GetTraceConfig_BackgroundTrigger(int period_ms) {
+    return StringPrintf(
+        "{"
+          "\"enable_argument_filter\":false,"
+          "\"enable_sampling\":false,"
+          "\"enable_systrace\":false,"
+          "\"included_categories\":["
+            "\"%s\""
+          "],"
+          "\"memory_dump_config\":{"
+             "\"allowed_dump_modes\":[\"background\"],"
+             "\"triggers\":["
+              "{"
+                "\"mode\":\"background\","
+                "\"periodic_interval_ms\":%d"
+              "}"
+            "]"
+          "},"
+          "\"record_mode\":\"record-until-full\""
+        "}", MemoryDumpManager::kTraceCategory, period_ms);
+  }
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_CONFIG_MEMORY_TEST_UTIL_H_
diff --git a/libchrome/base/trace_event/trace_config_unittest.cc b/libchrome/base/trace_event/trace_config_unittest.cc
new file mode 100644
index 0000000..4b46b2f
--- /dev/null
+++ b/libchrome/base/trace_event/trace_config_unittest.cc
@@ -0,0 +1,685 @@
+// 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 <stddef.h>
+
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_config_memory_test_util.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,"
+    "\"record_mode\":\"record-until-full\""
+  "}";
+
+const char kCustomTraceConfigString[] =
+  "{"
+    "\"enable_argument_filter\":true,"
+    "\"enable_sampling\":true,"
+    "\"enable_systrace\":true,"
+    "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
+    "\"included_categories\":[\"included\","
+                            "\"inc_pattern*\","
+                            "\"disabled-by-default-cc\","
+                            "\"disabled-by-default-memory-infra\"],"
+    "\"memory_dump_config\":{"
+      "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
+      "\"heap_profiler_options\":{"
+        "\"breakdown_threshold_bytes\":10240"
+      "},"
+      "\"triggers\":["
+        "{\"mode\":\"light\",\"periodic_interval_ms\":50},"
+        "{\"mode\":\"detailed\",\"periodic_interval_ms\":1000}"
+      "]"
+    "},"
+    "\"record_mode\":\"record-continuously\","
+    "\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
+  "}";
+
+void CheckDefaultTraceConfigBehavior(const TraceConfig& tc) {
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+
+  // Default trace config enables every category filter except the
+  // disabled-by-default-* ones.
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("not-excluded-category"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,not-excluded-category"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,disabled-by-default-cc"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled(
+      "disabled-by-default-cc,disabled-by-default-cc2"));
+}
+
+}  // 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("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) {
+  TraceConfig tc;
+  EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  CheckDefaultTraceConfigBehavior(tc);
+
+  // Constructors from category filter string and trace option string.
+  TraceConfig tc_asterisk("*", "");
+  EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str());
+  CheckDefaultTraceConfigBehavior(tc_asterisk);
+
+  TraceConfig tc_empty_category_filter("", "");
+  EXPECT_STREQ("", tc_empty_category_filter.ToCategoryFilterString().c_str());
+  EXPECT_STREQ(kDefaultTraceConfigString,
+               tc_empty_category_filter.ToString().c_str());
+  CheckDefaultTraceConfigBehavior(tc_empty_category_filter);
+
+  // Constructor from JSON formated config string.
+  TraceConfig tc_empty_json_string("");
+  EXPECT_STREQ("", tc_empty_json_string.ToCategoryFilterString().c_str());
+  EXPECT_STREQ(kDefaultTraceConfigString,
+               tc_empty_json_string.ToString().c_str());
+  CheckDefaultTraceConfigBehavior(tc_empty_json_string);
+
+  // Constructor from dictionary value.
+  DictionaryValue dict;
+  TraceConfig tc_dict(dict);
+  EXPECT_STREQ("", tc_dict.ToCategoryFilterString().c_str());
+  EXPECT_STREQ(kDefaultTraceConfigString, tc_dict.ToString().c_str());
+  CheckDefaultTraceConfigBehavior(tc_dict);
+}
+
+TEST(TraceConfigTest, EmptyAndAsteriskCategoryFilterString) {
+  TraceConfig tc_empty("", "");
+  TraceConfig tc_asterisk("*", "");
+
+  EXPECT_STREQ("", tc_empty.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str());
+
+  // Both fall back to default config.
+  CheckDefaultTraceConfigBehavior(tc_empty);
+  CheckDefaultTraceConfigBehavior(tc_asterisk);
+
+  // They differ only for internal checking.
+  EXPECT_FALSE(tc_empty.IsCategoryEnabled("Category1"));
+  EXPECT_FALSE(tc_empty.IsCategoryEnabled("not-excluded-category"));
+  EXPECT_TRUE(tc_asterisk.IsCategoryEnabled("Category1"));
+  EXPECT_TRUE(tc_asterisk.IsCategoryEnabled("not-excluded-category"));
+}
+
+TEST(TraceConfigTest, DisabledByDefaultCategoryFilterString) {
+  TraceConfig tc("foo,disabled-by-default-foo", "");
+  EXPECT_STREQ("foo,disabled-by-default-foo",
+               tc.ToCategoryFilterString().c_str());
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("bar"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar"));
+
+  // Enabling only the disabled-by-default-* category means the default ones
+  // are also enabled.
+  tc = TraceConfig("disabled-by-default-foo", "");
+  EXPECT_STREQ("disabled-by-default-foo", tc.ToCategoryFilterString().c_str());
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("bar"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar"));
+}
+
+TEST(TraceConfigTest, TraceConfigFromDict) {
+  // Passing in empty dictionary will result in default trace config.
+  DictionaryValue dict;
+  TraceConfig tc(dict);
+  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("", tc.ToCategoryFilterString().c_str());
+
+  std::unique_ptr<Value> default_value(
+      JSONReader::Read(kDefaultTraceConfigString));
+  DCHECK(default_value);
+  const DictionaryValue* default_dict = nullptr;
+  bool is_dict = default_value->GetAsDictionary(&default_dict);
+  DCHECK(is_dict);
+  TraceConfig default_tc(*default_dict);
+  EXPECT_STREQ(kDefaultTraceConfigString, default_tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, default_tc.GetTraceRecordMode());
+  EXPECT_FALSE(default_tc.IsSamplingEnabled());
+  EXPECT_FALSE(default_tc.IsSystraceEnabled());
+  EXPECT_FALSE(default_tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", default_tc.ToCategoryFilterString().c_str());
+
+  std::unique_ptr<Value> custom_value(
+      JSONReader::Read(kCustomTraceConfigString));
+  DCHECK(custom_value);
+  const DictionaryValue* custom_dict = nullptr;
+  is_dict = custom_value->GetAsDictionary(&custom_dict);
+  DCHECK(is_dict);
+  TraceConfig custom_tc(*custom_dict);
+  EXPECT_STREQ(kCustomTraceConfigString, custom_tc.ToString().c_str());
+  EXPECT_EQ(RECORD_CONTINUOUSLY, custom_tc.GetTraceRecordMode());
+  EXPECT_TRUE(custom_tc.IsSamplingEnabled());
+  EXPECT_TRUE(custom_tc.IsSystraceEnabled());
+  EXPECT_TRUE(custom_tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,"
+               "disabled-by-default-cc,disabled-by-default-memory-infra,"
+               "-excluded,-exc_pattern*,"
+               "DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
+               custom_tc.ToCategoryFilterString().c_str());
+}
+
+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("", tc.ToCategoryFilterString().c_str());
+  CheckDefaultTraceConfigBehavior(tc);
+
+  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("", tc.ToCategoryFilterString().c_str());
+  CheckDefaultTraceConfigBehavior(tc);
+
+  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("", tc.ToCategoryFilterString().c_str());
+  CheckDefaultTraceConfigBehavior(tc);
+
+  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("", tc.ToCategoryFilterString().c_str());
+  CheckDefaultTraceConfigBehavior(tc);
+
+  // 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());
+  CheckDefaultTraceConfigBehavior(tc);
+
+  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());
+  CheckDefaultTraceConfigBehavior(tc);
+
+  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\":[\"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"));
+
+  // Excluding categories won't enable disabled-by-default ones with the
+  // excluded category is also present in the group.
+  tc = TraceConfig("-excluded", "");
+  EXPECT_STREQ("-excluded", tc.ToCategoryFilterString().c_str());
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,disabled-by-default-cc"));
+}
+
+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());
+}
+
+TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) {
+  std::string tc_str1 =
+      TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(200, 2000);
+  TraceConfig tc1(tc_str1);
+  EXPECT_EQ(tc_str1, tc1.ToString());
+  EXPECT_TRUE(tc1.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+  ASSERT_EQ(2u, tc1.memory_dump_config_.triggers.size());
+
+  EXPECT_EQ(200u, tc1.memory_dump_config_.triggers[0].periodic_interval_ms);
+  EXPECT_EQ(MemoryDumpLevelOfDetail::LIGHT,
+            tc1.memory_dump_config_.triggers[0].level_of_detail);
+
+  EXPECT_EQ(2000u, tc1.memory_dump_config_.triggers[1].periodic_interval_ms);
+  EXPECT_EQ(MemoryDumpLevelOfDetail::DETAILED,
+            tc1.memory_dump_config_.triggers[1].level_of_detail);
+  EXPECT_EQ(
+      2048u,
+      tc1.memory_dump_config_.heap_profiler_options.breakdown_threshold_bytes);
+
+  std::string tc_str2 =
+      TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger(
+          1 /* period_ms */);
+  TraceConfig tc2(tc_str2);
+  EXPECT_EQ(tc_str2, tc2.ToString());
+  EXPECT_TRUE(tc2.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+  ASSERT_EQ(1u, tc2.memory_dump_config_.triggers.size());
+  EXPECT_EQ(1u, tc2.memory_dump_config_.triggers[0].periodic_interval_ms);
+  EXPECT_EQ(MemoryDumpLevelOfDetail::BACKGROUND,
+            tc2.memory_dump_config_.triggers[0].level_of_detail);
+}
+
+TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) {
+  // Empty trigger list should also be specified when converting back to string.
+  TraceConfig tc(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
+  EXPECT_EQ(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers(),
+            tc.ToString());
+  EXPECT_EQ(0u, tc.memory_dump_config_.triggers.size());
+  EXPECT_EQ(TraceConfig::MemoryDumpConfig::HeapProfiler
+            ::kDefaultBreakdownThresholdBytes,
+            tc.memory_dump_config_.heap_profiler_options
+            .breakdown_threshold_bytes);
+}
+
+TEST(TraceConfigTest, LegacyStringToMemoryDumpConfig) {
+  TraceConfig tc(MemoryDumpManager::kTraceCategory, "");
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
+  EXPECT_NE(std::string::npos, tc.ToString().find("memory_dump_config"));
+  EXPECT_EQ(2u, tc.memory_dump_config_.triggers.size());
+  EXPECT_EQ(TraceConfig::MemoryDumpConfig::HeapProfiler
+            ::kDefaultBreakdownThresholdBytes,
+            tc.memory_dump_config_.heap_profiler_options
+            .breakdown_threshold_bytes);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_event.gypi b/libchrome/base/trace_event/trace_event.gypi
new file mode 100644
index 0000000..f915780
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event.gypi
@@ -0,0 +1,107 @@
+# 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/blame_context.cc',
+      'trace_event/blame_context.h',
+      'trace_event/common/trace_event_common.h',
+      'trace_event/heap_profiler.h',
+      'trace_event/heap_profiler_allocation_context.cc',
+      'trace_event/heap_profiler_allocation_context.h',
+      'trace_event/heap_profiler_allocation_context_tracker.cc',
+      'trace_event/heap_profiler_allocation_context_tracker.h',
+      'trace_event/heap_profiler_allocation_register.cc',
+      'trace_event/heap_profiler_allocation_register_posix.cc',
+      'trace_event/heap_profiler_allocation_register_win.cc',
+      'trace_event/heap_profiler_allocation_register.h',
+      'trace_event/heap_profiler_heap_dump_writer.cc',
+      'trace_event/heap_profiler_heap_dump_writer.h',
+      'trace_event/heap_profiler_stack_frame_deduplicator.cc',
+      'trace_event/heap_profiler_stack_frame_deduplicator.h',
+      'trace_event/heap_profiler_type_name_deduplicator.cc',
+      'trace_event/heap_profiler_type_name_deduplicator.h',
+      '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.cc',
+      'trace_event/memory_dump_request_args.h',
+      'trace_event/memory_dump_session_state.cc',
+      'trace_event/memory_dump_session_state.h',
+      'trace_event/memory_infra_background_whitelist.cc',
+      'trace_event/memory_infra_background_whitelist.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_totals.cc',
+      'trace_event/process_memory_totals.h',
+      'trace_event/trace_buffer.cc',
+      'trace_event/trace_buffer.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_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_log.cc',
+      'trace_event/trace_log.h',
+      'trace_event/trace_log_constants.cc',
+      'trace_event/trace_sampling_thread.cc',
+      'trace_event/trace_sampling_thread.h',
+      'trace_event/tracing_agent.cc',
+      'trace_event/tracing_agent.h',
+      'trace_event/winheap_dump_provider_win.cc',
+      'trace_event/winheap_dump_provider_win.h',
+    ],
+    'trace_event_test_sources' : [
+      'trace_event/blame_context_unittest.cc',
+      'trace_event/heap_profiler_allocation_context_tracker_unittest.cc',
+      'trace_event/heap_profiler_allocation_register_unittest.cc',
+      'trace_event/heap_profiler_heap_dump_writer_unittest.cc',
+      'trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc',
+      'trace_event/heap_profiler_type_name_deduplicator_unittest.cc',
+      'trace_event/java_heap_dump_provider_android_unittest.cc',
+      'trace_event/memory_allocator_dump_unittest.cc',
+      'trace_event/memory_dump_manager_unittest.cc',
+      'trace_event/process_memory_dump_unittest.cc',
+      'trace_event/trace_config_memory_test_util.h',
+      'trace_event/trace_config_unittest.cc',
+      'trace_event/trace_event_argument_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/winheap_dump_provider_win_unittest.cc',
+    ],
+    'conditions': [
+      ['OS == "linux" or OS=="android" or OS=="mac" or OS=="ios"', {
+        'trace_event_sources': [
+          'trace_event/malloc_dump_provider.cc',
+          'trace_event/malloc_dump_provider.h',
+        ],
+      }],
+      ['OS == "android"', {
+        'trace_event_test_sources' : [
+          'trace_event/trace_event_android_unittest.cc',
+        ],
+      }],
+    ],
+  },
+}
diff --git a/libchrome/base/trace_event/trace_event.h b/libchrome/base/trace_event/trace_event.h
new file mode 100644
index 0000000..a075898
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event.h
@@ -0,0 +1,1091 @@
+// Copyright (c) 2012 The Chromium Authors. All 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_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_H_
+
+// This header file defines implementation details of how the trace macros in
+// trace_event_common.h collect and store trace events. Anything not
+// implementation-specific should go in trace_event_common.h instead of here.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/atomicops.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/trace_event/common/trace_event_common.h"
+#include "base/trace_event/heap_profiler.h"
+#include "base/trace_event/trace_event_system_stats_monitor.h"
+#include "base/trace_event/trace_log.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)
+
+// By default, uint64_t 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)
+
+// By default, trace IDs are eventually converted to a single 64-bit number. Use
+// this macro to add a scope string.
+#define TRACE_ID_WITH_SCOPE(scope, id) \
+    trace_event_internal::TraceID::WithScope(scope, id)
+
+// 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);
+
+#define TRACE_EVENT_API_CURRENT_THREAD_ID \
+  static_cast<int>(base::PlatformThread::CurrentId())
+
+#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))
+
+////////////////////////////////////////////////////////////////////////////////
+// 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,
+//                    const char* scope,
+//                    unsigned long long id,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    std::unique_ptr<ConvertableToTraceFormat>*
+//                    convertable_values,
+//                    unsigned int 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_BIND_ID(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    const char* scope,
+//                    unsigned long long id,
+//                    unsigned long long bind_id,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    std::unique_ptr<ConvertableToTraceFormat>*
+//                    convertable_values,
+//                    unsigned int flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID \
+  base::trace_event::TraceLog::GetInstance()->AddTraceEventWithBindId
+
+// Add a trace event to the platform tracing system overriding the pid.
+// The resulting event will have tid = pid == (process_id passed here).
+// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    const char* scope,
+//                    unsigned long long id,
+//                    int process_id,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    std::unique_ptr<ConvertableToTraceFormat>*
+//                    convertable_values,
+//                    unsigned int flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID \
+  base::trace_event::TraceLog::GetInstance()->AddTraceEventWithProcessId
+
+// 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,
+//                    const char* scope,
+//                    unsigned long long id,
+//                    int thread_id,
+//                    const TimeTicks& timestamp,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    std::unique_ptr<ConvertableToTraceFormat>*
+//                    convertable_values,
+//                    unsigned int 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
+
+// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
+// on the convertable value will be called at flush time.
+// TRACE_EVENT_API_ADD_METADATA_EVENT(
+//     const unsigned char* category_group_enabled,
+//     const char* event_name,
+//     const char* arg_name,
+//     std::unique_ptr<ConvertableToTraceFormat> arg_value)
+#define TRACE_EVENT_API_ADD_METADATA_EVENT \
+    trace_event_internal::AddMetadataEvent
+
+// 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::kGlobalScope, trace_event_internal::kNoId, \
+            flags, trace_event_internal::kNoId, ##__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::kGlobalScope, trace_event_internal::kNoId, \
+              TRACE_EVENT_FLAG_NONE, trace_event_internal::kNoId, \
+              ##__VA_ARGS__); \
+      INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
+          INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
+    }
+
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW( \
+    category_group, name, bind_id, flow_flags, ...) \
+  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()) { \
+    unsigned int trace_event_flags = flow_flags; \
+    trace_event_internal::TraceID trace_event_bind_id(bind_id, \
+                                                      &trace_event_flags); \
+    base::trace_event::TraceEventHandle h = \
+        trace_event_internal::AddTraceEvent( \
+            TRACE_EVENT_PHASE_COMPLETE, \
+            INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+            trace_event_internal::kGlobalScope, trace_event_internal::kNoId, \
+            trace_event_flags, trace_event_bind_id.raw_id(), ##__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 int 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.scope(), trace_event_trace_id.raw_id(), \
+            trace_event_flags, trace_event_internal::kNoId, ##__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_TIMESTAMP(phase, category_group, name, \
+                                                timestamp, flags, ...)       \
+  do {                                                                       \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                  \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) {  \
+      trace_event_internal::AddTraceEventWithThreadIdAndTimestamp(           \
+          phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,     \
+          trace_event_internal::kGlobalScope, trace_event_internal::kNoId,   \
+          TRACE_EVENT_API_CURRENT_THREAD_ID,                                 \
+          base::TimeTicks::FromInternalValue(timestamp),                     \
+          flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP,                       \
+          trace_event_internal::kNoId, ##__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 int 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.scope(), trace_event_trace_id.raw_id(),        \
+          thread_id, base::TimeTicks::FromInternalValue(timestamp),           \
+          trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP,            \
+          trace_event_internal::kNoId, ##__VA_ARGS__);                        \
+    }                                                                         \
+  } while (0)
+
+// Implementation detail: internal macro to create static category and add
+// metadata event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_METADATA_ADD(category_group, name, ...)        \
+  do {                                                                      \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                 \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+      TRACE_EVENT_API_ADD_METADATA_EVENT(                                   \
+          INTERNAL_TRACE_EVENT_UID(category_group_enabled), name,           \
+          ##__VA_ARGS__);                                                   \
+    }                                                                       \
+  } while (0)
+
+// Implementation detail: internal macro to enter and leave a
+// context based on the current scope.
+#define INTERNAL_TRACE_EVENT_SCOPED_CONTEXT(category_group, name, context) \
+  struct INTERNAL_TRACE_EVENT_UID(ScopedContext) {                         \
+   public:                                                                 \
+    INTERNAL_TRACE_EVENT_UID(ScopedContext)(uint64_t cid) : cid_(cid) {    \
+      TRACE_EVENT_ENTER_CONTEXT(category_group, name, cid_);               \
+    }                                                                      \
+    ~INTERNAL_TRACE_EVENT_UID(ScopedContext)() {                           \
+      TRACE_EVENT_LEAVE_CONTEXT(category_group, name, cid_);               \
+    }                                                                      \
+                                                                           \
+   private:                                                                \
+    uint64_t cid_;                                                         \
+    /* Local class friendly DISALLOW_COPY_AND_ASSIGN */                    \
+    INTERNAL_TRACE_EVENT_UID(ScopedContext)                                \
+    (const INTERNAL_TRACE_EVENT_UID(ScopedContext)&) {};                   \
+    void operator=(const INTERNAL_TRACE_EVENT_UID(ScopedContext)&) {};     \
+  };                                                                       \
+  INTERNAL_TRACE_EVENT_UID(ScopedContext)                                  \
+  INTERNAL_TRACE_EVENT_UID(scoped_context)(context.raw_id());
+
+// Implementation detail: internal macro to trace a task execution with the
+// location where it was posted from.
+#define INTERNAL_TRACE_TASK_EXECUTION(run_function, task)                 \
+  TRACE_EVENT2("toplevel", run_function, "src_file",                      \
+               (task).posted_from.file_name(), "src_func",                \
+               (task).posted_from.function_name());                       \
+  TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION INTERNAL_TRACE_EVENT_UID( \
+      task_event)((task).posted_from.file_name());
+
+namespace trace_event_internal {
+
+// Specify these values when the corresponding argument of AddTraceEvent is not
+// used.
+const int kZeroNumArgs = 0;
+const std::nullptr_t kGlobalScope = nullptr;
+const unsigned long long kNoId = 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 WithScope {
+   public:
+    WithScope(const char* scope, unsigned long long raw_id)
+        : scope_(scope), raw_id_(raw_id) {}
+    unsigned long long raw_id() const { return raw_id_; }
+    const char* scope() const { return scope_; }
+   private:
+    const char* scope_ = nullptr;
+    unsigned long long raw_id_;
+  };
+
+  class DontMangle {
+   public:
+    explicit DontMangle(const void* raw_id)
+        : raw_id_(static_cast<unsigned long long>(
+              reinterpret_cast<uintptr_t>(raw_id))) {}
+    explicit DontMangle(unsigned long long raw_id) : raw_id_(raw_id) {}
+    explicit DontMangle(unsigned long raw_id) : raw_id_(raw_id) {}
+    explicit DontMangle(unsigned int raw_id) : raw_id_(raw_id) {}
+    explicit DontMangle(unsigned short raw_id) : raw_id_(raw_id) {}
+    explicit DontMangle(unsigned char raw_id) : raw_id_(raw_id) {}
+    explicit DontMangle(long long raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit DontMangle(long raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit DontMangle(int raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit DontMangle(short raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit DontMangle(signed char raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit DontMangle(WithScope scoped_id)
+        : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
+    const char* scope() const { return scope_; }
+    unsigned long long raw_id() const { return raw_id_; }
+   private:
+    const char* scope_ = nullptr;
+    unsigned long long raw_id_;
+  };
+
+  class ForceMangle {
+   public:
+    explicit ForceMangle(unsigned long long raw_id) : raw_id_(raw_id) {}
+    explicit ForceMangle(unsigned long raw_id) : raw_id_(raw_id) {}
+    explicit ForceMangle(unsigned int raw_id) : raw_id_(raw_id) {}
+    explicit ForceMangle(unsigned short raw_id) : raw_id_(raw_id) {}
+    explicit ForceMangle(unsigned char raw_id) : raw_id_(raw_id) {}
+    explicit ForceMangle(long long raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit ForceMangle(long raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit ForceMangle(int raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit ForceMangle(short raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    explicit ForceMangle(signed char raw_id)
+        : raw_id_(static_cast<unsigned long long>(raw_id)) {}
+    unsigned long long raw_id() const { return raw_id_; }
+   private:
+    unsigned long long raw_id_;
+  };
+  TraceID(const void* raw_id, unsigned int* flags)
+      : raw_id_(static_cast<unsigned long long>(
+                reinterpret_cast<uintptr_t>(raw_id))) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  TraceID(ForceMangle raw_id, unsigned int* flags) : raw_id_(raw_id.raw_id()) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  TraceID(DontMangle maybe_scoped_id, unsigned int* /*flags*/)
+      : scope_(maybe_scoped_id.scope()), raw_id_(maybe_scoped_id.raw_id()) {}
+  TraceID(unsigned long long raw_id, unsigned int* flags) : raw_id_(raw_id) {
+    (void)flags;
+  }
+  TraceID(unsigned long raw_id, unsigned int* flags) : raw_id_(raw_id) {
+    (void)flags;
+  }
+  TraceID(unsigned int raw_id, unsigned int* flags) : raw_id_(raw_id) {
+    (void)flags;
+  }
+  TraceID(unsigned short raw_id, unsigned int* flags) : raw_id_(raw_id) {
+    (void)flags;
+  }
+  TraceID(unsigned char raw_id, unsigned int* flags) : raw_id_(raw_id) {
+    (void)flags;
+  }
+  TraceID(long long raw_id, unsigned int* flags)
+      : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+  TraceID(long raw_id, unsigned int* flags)
+      : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+  TraceID(int raw_id, unsigned int* flags)
+      : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+  TraceID(short raw_id, unsigned int* flags)
+      : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+  TraceID(signed char raw_id, unsigned int* flags)
+      : raw_id_(static_cast<unsigned long long>(raw_id)) { (void)flags; }
+  TraceID(WithScope scoped_id, unsigned int* /*flags*/)
+      : scope_(scoped_id.scope()), raw_id_(scoped_id.raw_id()) {}
+
+  unsigned long long raw_id() const { return raw_id_; }
+  const char* scope() const { return scope_; }
+
+ private:
+  const char* scope_ = nullptr;
+  unsigned long long raw_id_;
+};
+
+// 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();
+}
+
+// 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.
+
+template <class ARG1_CONVERTABLE_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val) {
+  const int num_args = 1;
+  unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE };
+  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[1] = {std::move(arg1_val)};
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
+      timestamp, num_args, &arg1_name, arg_types, NULL, convertable_values,
+      flags);
+}
+
+template <class ARG1_TYPE, class ARG2_CONVERTABLE_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    std::unique_ptr<ARG2_CONVERTABLE_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]);
+  arg_types[1] = TRACE_VALUE_TYPE_CONVERTABLE;
+  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2] = {nullptr, std::move(arg2_val)};
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
+      timestamp, num_args, arg_names, arg_types, arg_values, convertable_values,
+      flags);
+}
+
+template <class ARG1_CONVERTABLE_TYPE, class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    std::unique_ptr<ARG1_CONVERTABLE_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];
+  arg_types[0] = TRACE_VALUE_TYPE_CONVERTABLE;
+  arg_values[0] = 0;
+  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
+  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2] = {std::move(arg1_val), nullptr};
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
+      timestamp, num_args, arg_names, arg_types, arg_values, convertable_values,
+      flags);
+}
+
+template <class ARG1_CONVERTABLE_TYPE, class ARG2_CONVERTABLE_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val,
+    const char* arg2_name,
+    std::unique_ptr<ARG2_CONVERTABLE_TYPE> 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 };
+  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2] = {std::move(arg1_val), std::move(arg2_val)};
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, scope, id, bind_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,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned int flags,
+    unsigned long long bind_id) {
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, scope, id, bind_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,
+    const char* scope,
+    unsigned long long id,
+    unsigned int flags,
+    unsigned long long bind_id) {
+  const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  const base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
+      bind_id);
+}
+
+template<class ARG1_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned int flags,
+    unsigned long long bind_id,
+    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, scope, id, bind_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,
+    const char* scope,
+    unsigned long long id,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
+      bind_id, arg1_name, arg1_val);
+}
+
+template <class ARG1_CONVERTABLE_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
+      bind_id, arg1_name, std::move(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,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const base::TimeTicks& timestamp,
+    unsigned int flags,
+    unsigned long long bind_id,
+    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, scope, id, bind_id, thread_id,
+      timestamp, num_args, arg_names, arg_types, arg_values, NULL, flags);
+}
+
+template <class ARG1_CONVERTABLE_TYPE, class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val,
+    const char* arg2_name,
+    const ARG2_TYPE& arg2_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
+      bind_id, arg1_name, std::move(arg1_val), arg2_name, arg2_val);
+}
+
+template <class ARG1_TYPE, class ARG2_CONVERTABLE_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
+      bind_id, arg1_name, arg1_val, arg2_name, std::move(arg2_val));
+}
+
+template <class ARG1_CONVERTABLE_TYPE, class ARG2_CONVERTABLE_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned int flags,
+    unsigned long long bind_id,
+    const char* arg1_name,
+    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val,
+    const char* arg2_name,
+    std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
+      bind_id, arg1_name, std::move(arg1_val), arg2_name, std::move(arg2_val));
+}
+
+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,
+    const char* scope,
+    unsigned long long id,
+    unsigned int flags,
+    unsigned long long bind_id,
+    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::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
+      bind_id, arg1_name, arg1_val, arg2_name, arg2_val);
+}
+
+template <class ARG1_CONVERTABLE_TYPE>
+static inline void AddMetadataEvent(
+    const unsigned char* category_group_enabled,
+    const char* event_name,
+    const char* arg_name,
+    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg_value) {
+  const char* arg_names[1] = {arg_name};
+  unsigned char arg_types[1] = {TRACE_VALUE_TYPE_CONVERTABLE};
+  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[1] = {std::move(arg_value)};
+  base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+      category_group_enabled, event_name,
+      1,  // num_args
+      arg_names, arg_types,
+      nullptr,  // arg_values
+      convertable_values, TRACE_EVENT_FLAG_NONE);
+}
+
+template <class ARG1_TYPE>
+static void AddMetadataEvent(const unsigned char* category_group_enabled,
+                             const char* event_name,
+                             const char* arg_name,
+                             const ARG1_TYPE& arg_val) {
+  const int num_args = 1;
+  const char* arg_names[1] = {arg_name};
+  unsigned char arg_types[1];
+  unsigned long long arg_values[1];
+  SetTraceValue(arg_val, &arg_types[0], &arg_values[0]);
+
+  base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+      category_group_enabled, event_name, num_args, arg_names, arg_types,
+      arg_values, nullptr, TRACE_EVENT_FLAG_NONE);
+}
+
+// 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/libchrome/base/trace_event/trace_event_argument.cc b/libchrome/base/trace_event/trace_event_argument.cc
new file mode 100644
index 0000000..336d964
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_argument.cc
@@ -0,0 +1,473 @@
+// 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 <stdint.h>
+
+#include <utility>
+
+#include "base/bits.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.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_t>(reinterpret_cast<uintptr_t>(ptr)));
+}
+
+inline void WriteKeyNameWithCopy(Pickle& pickle, base::StringPiece 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_t 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(base::StringPiece name, int value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameWithCopy(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(base::StringPiece name,
+                                          double value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameWithCopy(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(base::StringPiece name,
+                                           bool value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameWithCopy(pickle_, name);
+}
+
+void TracedValue::SetString(const char* name, base::StringPiece value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetStringWithCopiedName(base::StringPiece name,
+                                          base::StringPiece value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameWithCopy(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(base::StringPiece 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(base::StringPiece name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameWithCopy(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(base::StringPiece name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameWithCopy(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(base::StringPiece 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,
+                           std::unique_ptr<base::Value> value) {
+  SetBaseValueWithCopiedName(name, *value);
+}
+
+void TracedValue::SetBaseValueWithCopiedName(base::StringPiece 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 (const auto& 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 (const auto& base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+std::unique_ptr<base::Value> TracedValue::ToBaseValue() const {
+  std::unique_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->SetWithoutPathExpansion(ReadKeyName(it),
+                                            WrapUnique(new_dict));
+          stack.push_back(cur_dict);
+          cur_dict = new_dict;
+        } else {
+          cur_list->Append(WrapUnique(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->SetWithoutPathExpansion(ReadKeyName(it),
+                                            WrapUnique(new_list));
+          stack.push_back(cur_dict);
+          cur_dict = nullptr;
+          cur_list = new_list;
+        } else {
+          cur_list->Append(WrapUnique(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->SetBooleanWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendBoolean(value);
+        }
+      } break;
+
+      case kTypeInt: {
+        int value;
+        CHECK(it.ReadInt(&value));
+        if (cur_dict) {
+          cur_dict->SetIntegerWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendInteger(value);
+        }
+      } break;
+
+      case kTypeDouble: {
+        double value;
+        CHECK(it.ReadDouble(&value));
+        if (cur_dict) {
+          cur_dict->SetDoubleWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendDouble(value);
+        }
+      } break;
+
+      case kTypeString: {
+        std::string value;
+        CHECK(it.ReadString(&value));
+        if (cur_dict) {
+          cur_dict->SetStringWithoutPathExpansion(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendString(value);
+        }
+      } break;
+
+      default:
+        NOTREACHED();
+    }
+  }
+  DCHECK(stack.empty());
+  return std::move(root);
+}
+
+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",
+                /* allocated size */
+                pickle_.GetTotalAllocatedSize(),
+                /* resident size */
+                pickle_.size());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_event_argument.h b/libchrome/base/trace_event/trace_event_argument.h
new file mode 100644
index 0000000..81d8c01
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_argument.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_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/pickle.h"
+#include "base/strings/string_piece.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+
+class Value;
+
+namespace trace_event {
+
+class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
+ public:
+  TracedValue();
+  explicit TracedValue(size_t capacity);
+  ~TracedValue() override;
+
+  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, base::StringPiece 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(base::StringPiece name, int value);
+  void SetDoubleWithCopiedName(base::StringPiece name, double value);
+  void SetBooleanWithCopiedName(base::StringPiece name, bool value);
+  void SetStringWithCopiedName(base::StringPiece name,
+                               base::StringPiece value);
+  void SetValueWithCopiedName(base::StringPiece name,
+                              const TracedValue& value);
+  void BeginDictionaryWithCopiedName(base::StringPiece name);
+  void BeginArrayWithCopiedName(base::StringPiece name);
+
+  void AppendInteger(int);
+  void AppendDouble(double);
+  void AppendBoolean(bool);
+  void AppendString(base::StringPiece);
+  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, std::unique_ptr<base::Value> value);
+  void SetBaseValueWithCopiedName(base::StringPiece name,
+                                  const base::Value& value);
+  void AppendBaseValue(const base::Value& value);
+
+  // Public for tests only.
+  std::unique_ptr<base::Value> ToBaseValue() const;
+
+ private:
+  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/libchrome/base/trace_event/trace_event_argument_unittest.cc b/libchrome/base/trace_event/trace_event_argument_unittest.cc
new file mode 100644
index 0000000..61395f4
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_argument_unittest.cc
@@ -0,0 +1,165 @@
+// 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 <stddef.h>
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(TraceEventArgumentTest, FlatDictionary) {
+  std::unique_ptr<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, NoDotPathExpansion) {
+  std::unique_ptr<TracedValue> value(new TracedValue());
+  value->SetInteger("in.t", 2014);
+  value->SetDouble("doub.le", 0.0);
+  value->SetBoolean("bo.ol", true);
+  value->SetString("str.ing", "str.ing");
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "{\"bo.ol\":true,\"doub.le\":0.0,\"in.t\":2014,\"str.ing\":\"str.ing\"}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, Hierarchy) {
+  std::unique_ptr<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';
+
+  std::unique_ptr<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 = WrapUnique(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 = WrapUnique(new ListValue);
+  list_value->AppendBoolean(false);
+  list_value->AppendInteger(1);
+  list_value->AppendString("in_list");
+  list_value->Append(std::move(dict_value));
+
+  std::unique_ptr<TracedValue> value(new TracedValue());
+  value->BeginDictionary("outer_dict");
+  value->SetValue("inner_list", std::move(list_value));
+  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 = WrapUnique(new TracedValue());
+  dict_value->SetInteger("a", 1);
+
+  auto nested_dict_value = WrapUnique(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/libchrome/base/trace_event/trace_event_impl.cc b/libchrome/base/trace_event/trace_event_impl.cc
new file mode 100644
index 0000000..f469f2f
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_impl.cc
@@ -0,0 +1,426 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include "base/format_macros.h"
+#include "base/json/string_escape.h"
+#include "base/process/process_handle.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_log.h"
+
+namespace base {
+namespace trace_event {
+
+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)),
+      scope_(trace_event_internal::kGlobalScope),
+      id_(0u),
+      category_group_enabled_(NULL),
+      name_(NULL),
+      thread_id_(0),
+      flags_(0),
+      phase_(TRACE_EVENT_PHASE_BEGIN) {
+  for (int i = 0; i < kTraceMaxNumArgs; ++i)
+    arg_names_[i] = NULL;
+  memset(arg_values_, 0, sizeof(arg_values_));
+}
+
+TraceEvent::~TraceEvent() {
+}
+
+void TraceEvent::MoveFrom(std::unique_ptr<TraceEvent> other) {
+  timestamp_ = other->timestamp_;
+  thread_timestamp_ = other->thread_timestamp_;
+  duration_ = other->duration_;
+  scope_ = other->scope_;
+  id_ = other->id_;
+  category_group_enabled_ = other->category_group_enabled_;
+  name_ = other->name_;
+  if (other->flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID)
+    process_id_ = other->process_id_;
+  else
+    thread_id_ = other->thread_id_;
+  phase_ = other->phase_;
+  flags_ = other->flags_;
+  parameter_copy_storage_ = std::move(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] = std::move(other->convertable_values_[i]);
+  }
+}
+
+void TraceEvent::Initialize(
+    int thread_id,
+    TimeTicks timestamp,
+    ThreadTicks thread_timestamp,
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned long long bind_id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  timestamp_ = timestamp;
+  thread_timestamp_ = thread_timestamp;
+  duration_ = TimeDelta::FromInternalValue(-1);
+  scope_ = scope;
+  id_ = id;
+  category_group_enabled_ = category_group_enabled;
+  name_ = name;
+  thread_id_ = thread_id;
+  phase_ = phase;
+  flags_ = flags;
+  bind_id_ = bind_id;
+
+  // 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] = std::move(convertable_values[i]);
+    } else {
+      arg_values_[i].as_uint = arg_values[i];
+      convertable_values_[i].reset();
+    }
+  }
+  for (; i < kTraceMaxNumArgs; ++i) {
+    arg_names_[i] = NULL;
+    arg_values_[i].as_uint = 0u;
+    convertable_values_[i].reset();
+    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) + GetAllocLength(scope);
+    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_.reset(new std::string);
+    parameter_copy_storage_->resize(alloc_size);
+    char* ptr = string_as_array(parameter_copy_storage_.get());
+    const char* end = ptr + alloc_size;
+    if (copy) {
+      CopyTraceEventParameter(&ptr, &name_, end);
+      CopyTraceEventParameter(&ptr, &scope_, 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_.reset();
+  for (int i = 0; i < kTraceMaxNumArgs; ++i)
+    convertable_values_[i].reset();
+}
+
+void TraceEvent::UpdateDuration(const TimeTicks& now,
+                                const ThreadTicks& thread_now) {
+  DCHECK_EQ(duration_.ToInternalValue(), -1);
+  duration_ = now - timestamp_;
+
+  // |thread_timestamp_| can be empty if the thread ticks clock wasn't
+  // initialized when it was recorded.
+  if (thread_timestamp_ != ThreadTicks())
+    thread_duration_ = thread_now - thread_timestamp_;
+}
+
+void TraceEvent::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("TraceEvent", sizeof(*this));
+
+  if (parameter_copy_storage_)
+    overhead->AddString(*parameter_copy_storage_);
+
+  for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
+    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+      convertable_values_[i]->EstimateTraceMemoryOverhead(overhead);
+  }
+}
+
+// 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_t>(value.as_uint));
+      break;
+    case TRACE_VALUE_TYPE_INT:
+      StringAppendF(out, "%" PRId64, static_cast<int64_t>(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_t>(reinterpret_cast<uintptr_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_t time_int64 = timestamp_.ToInternalValue();
+  int process_id;
+  int thread_id;
+  if ((flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID) &&
+      process_id_ != kNullProcessId) {
+    process_id = process_id_;
+    thread_id = -1;
+  } else {
+    process_id = TraceLog::GetInstance()->process_id();
+    thread_id = thread_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\":",
+                process_id, thread_id, time_int64, phase_, category_group_name);
+  EscapeJSONString(name_, true, out);
+  *out += ",\"args\":";
+
+  // Output argument names and values, stop at first NULL argument name.
+  // TODO(oysteine): The dual predicates here is a bit ugly; if the filtering
+  // capabilities need to grow even more precise we should rethink this
+  // approach
+  ArgumentNameFilterPredicate argument_name_filter_predicate;
+  bool strip_args =
+      arg_names_[0] && !argument_filter_predicate.is_null() &&
+      !argument_filter_predicate.Run(category_group_name, name_,
+                                     &argument_name_filter_predicate);
+
+  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 (argument_name_filter_predicate.is_null() ||
+          argument_name_filter_predicate.Run(arg_names_[i])) {
+        if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+          convertable_values_[i]->AppendAsTraceFormat(out);
+        else
+          AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+      } else {
+        *out += "\"__stripped__\"";
+      }
+    }
+
+    *out += "}";
+  }
+
+  if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
+    int64_t duration = duration_.ToInternalValue();
+    if (duration != -1)
+      StringAppendF(out, ",\"dur\":%" PRId64, duration);
+    if (!thread_timestamp_.is_null()) {
+      int64_t 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_t 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) {
+    if (scope_ != trace_event_internal::kGlobalScope)
+      StringAppendF(out, ",\"scope\":\"%s\"", scope_);
+    StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64_t>(id_));
+  }
+
+  if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+    StringAppendF(out, ",\"bp\":\"e\"");
+
+  if ((flags_ & TRACE_EVENT_FLAG_FLOW_OUT) ||
+      (flags_ & TRACE_EVENT_FLAG_FLOW_IN)) {
+    StringAppendF(out, ",\"bind_id\":\"0x%" PRIx64 "\"",
+                  static_cast<uint64_t>(bind_id_));
+  }
+  if (flags_ & TRACE_EVENT_FLAG_FLOW_IN)
+    StringAppendF(out, ",\"flow_in\":true");
+  if (flags_ & TRACE_EVENT_FLAG_FLOW_OUT)
+    StringAppendF(out, ",\"flow_out\":true");
+
+  // 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 << "}";
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_event_impl.h b/libchrome/base/trace_event/trace_event_impl.h
new file mode 100644
index 0000000..4382217
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_impl.h
@@ -0,0 +1,189 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.h>
+
+#include <memory>
+#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/macros.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/trace_event_memory_overhead.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class WaitableEvent;
+class MessageLoop;
+
+namespace trace_event {
+
+typedef base::Callback<bool(const char* arg_name)> ArgumentNameFilterPredicate;
+
+typedef base::Callback<bool(const char* category_group_name,
+                            const char* event_name,
+                            ArgumentNameFilterPredicate*)>
+    ArgumentFilterPredicate;
+
+// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
+// class must implement this interface.
+class BASE_EXPORT ConvertableToTraceFormat {
+ public:
+  ConvertableToTraceFormat() {}
+  virtual ~ConvertableToTraceFormat() {}
+
+  // 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;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormat);
+};
+
+const int kTraceMaxNumArgs = 2;
+
+struct TraceEventHandle {
+  uint32_t chunk_seq;
+  // These numbers of bits must be kept consistent with
+  // TraceBufferChunk::kMaxTrunkIndex and
+  // TraceBufferChunk::kTraceBufferChunkSize (in trace_buffer.h).
+  unsigned chunk_index : 26;
+  unsigned event_index : 6;
+};
+
+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();
+
+  void MoveFrom(std::unique_ptr<TraceEvent> other);
+
+  void Initialize(int thread_id,
+                  TimeTicks timestamp,
+                  ThreadTicks thread_timestamp,
+                  char phase,
+                  const unsigned char* category_group_enabled,
+                  const char* name,
+                  const char* scope,
+                  unsigned long long id,
+                  unsigned long long bind_id,
+                  int num_args,
+                  const char** arg_names,
+                  const unsigned char* arg_types,
+                  const unsigned long long* arg_values,
+                  std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+                  unsigned int flags);
+
+  void Reset();
+
+  void UpdateDuration(const TimeTicks& now, const ThreadTicks& thread_now);
+
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  // Serialize event data to JSON
+  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);
+
+  TimeTicks 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_; }
+  const char* scope() const { return scope_; }
+  unsigned long long id() const { return id_; }
+  unsigned int flags() const { return flags_; }
+
+  // Exposed for unittesting:
+
+  const std::string* 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.
+  TimeTicks timestamp_;
+  ThreadTicks thread_timestamp_;
+  TimeDelta duration_;
+  TimeDelta thread_duration_;
+  // scope_ and id_ can be used to store phase-specific data.
+  const char* scope_;
+  unsigned long long id_;
+  TraceValue arg_values_[kTraceMaxNumArgs];
+  const char* arg_names_[kTraceMaxNumArgs];
+  std::unique_ptr<ConvertableToTraceFormat>
+      convertable_values_[kTraceMaxNumArgs];
+  const unsigned char* category_group_enabled_;
+  const char* name_;
+  std::unique_ptr<std::string> parameter_copy_storage_;
+  // Depending on TRACE_EVENT_FLAG_HAS_PROCESS_ID the event will have either:
+  //  tid: thread_id_, pid: current_process_id (default case).
+  //  tid: -1, pid: process_id_ (when flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID).
+  union {
+    int thread_id_;
+    int process_id_;
+  };
+  unsigned int flags_;
+  unsigned long long bind_id_;
+  unsigned char arg_types_[kTraceMaxNumArgs];
+  char phase_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEvent);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
diff --git a/libchrome/base/trace_event/trace_event_memory_overhead.cc b/libchrome/base/trace_event/trace_event_memory_overhead.cc
new file mode 100644
index 0000000..23579cb
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_memory_overhead.cc
@@ -0,0 +1,156 @@
+// 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/bits.h"
+#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 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 strings seem to malloc() multiples of 16 bytes.
+  const size_t capacity = bits::Align(str.capacity(), 16);
+  Add("std::string", sizeof(std::string) + std::max<size_t>(capacity, 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 auto& 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);
+}
+
+size_t TraceEventMemoryOverhead::GetCount(const char* object_type) const {
+  const auto& it = allocated_objects_.find(object_type);
+  if (it == allocated_objects_.end())
+    return 0u;
+  return it->second.count;
+}
+
+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::kNameObjectCount,
+                   MemoryAllocatorDump::kUnitsObjects, it.second.count);
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_event_memory_overhead.h b/libchrome/base/trace_event/trace_event_memory_overhead.h
new file mode 100644
index 0000000..a69c93f
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_memory_overhead.h
@@ -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.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+#include "base/macros.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();
+
+  // Retrieves the count, that is, the count of Add*(|object_type|, ...) calls.
+  size_t GetCount(const char* object_type) const;
+
+  // 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/libchrome/base/trace_event/trace_event_synthetic_delay.cc b/libchrome/base/trace_event/trace_event_synthetic_delay.cc
new file mode 100644
index 0000000..b6ce284
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_synthetic_delay.cc
@@ -0,0 +1,231 @@
+// 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/macros.h"
+#include "base/memory/singleton.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.
+  TimeTicks Now() override;
+
+ private:
+  TraceEventSyntheticDelayRegistry();
+
+  friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
+
+  Lock lock_;
+  TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
+  TraceEventSyntheticDelay dummy_delay_;
+  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(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.
+  if (!target_duration_.ToInternalValue())
+    return;
+
+  TimeTicks start_time = clock_->Now();
+  {
+    AutoLock lock(lock_);
+    if (++begin_count_ != 1)
+      return;
+    end_time_ = CalculateEndTimeLocked(start_time);
+  }
+}
+
+void TraceEventSyntheticDelay::BeginParallel(TimeTicks* out_end_time) {
+  // See note in Begin().
+  if (!target_duration_.ToInternalValue()) {
+    *out_end_time = TimeTicks();
+    return;
+  }
+
+  TimeTicks start_time = clock_->Now();
+  {
+    AutoLock lock(lock_);
+    *out_end_time = CalculateEndTimeLocked(start_time);
+  }
+}
+
+void TraceEventSyntheticDelay::End() {
+  // See note in Begin().
+  if (!target_duration_.ToInternalValue())
+    return;
+
+  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(TimeTicks end_time) {
+  if (!end_time.is_null())
+    ApplyDelay(end_time);
+}
+
+TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
+    TimeTicks start_time) {
+  if (mode_ == ONE_SHOT && trigger_count_++)
+    return TimeTicks();
+  else if (mode_ == ALTERNATING && trigger_count_++ % 2)
+    return TimeTicks();
+  return start_time + target_duration_;
+}
+
+void TraceEventSyntheticDelay::ApplyDelay(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 = 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 = 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);
+  subtle::Release_Store(&delay_count_, delay_count + 1);
+  return &delays_[delay_count];
+}
+
+TimeTicks TraceEventSyntheticDelayRegistry::Now() {
+  return TimeTicks::Now();
+}
+
+void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
+  AutoLock lock(lock_);
+  int delay_count = subtle::Acquire_Load(&delay_count_);
+  for (int i = 0; i < delay_count; ++i) {
+    delays_[i].SetTargetDuration(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/libchrome/base/trace_event/trace_event_synthetic_delay.h b/libchrome/base/trace_event/trace_event_synthetic_delay.h
new file mode 100644
index 0000000..59e2842
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_synthetic_delay.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.
+
+// 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/macros.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/libchrome/base/trace_event/trace_event_synthetic_delay_unittest.cc b/libchrome/base/trace_event/trace_event_synthetic_delay_unittest.cc
new file mode 100644
index 0000000..97a4580
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_synthetic_delay_unittest.cc
@@ -0,0 +1,157 @@
+// 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 <stdint.h>
+
+#include "base/macros.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_t TestFunction() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY("test.Delay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+  int64_t AsyncTestFunctionBegin() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("test.AsyncDelay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+  int64_t 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/libchrome/base/trace_event/trace_event_system_stats_monitor.h b/libchrome/base/trace_event/trace_event_system_stats_monitor.h
new file mode 100644
index 0000000..14aa568
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_system_stats_monitor.h
@@ -0,0 +1,76 @@
+// 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/macros.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_log.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);
+
+  ~TraceEventSystemStatsMonitor() override;
+
+  // 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 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/libchrome/base/trace_event/trace_event_unittest.cc b/libchrome/base/trace_event/trace_event_unittest.cc
new file mode 100644
index 0000000..ff8ec2d
--- /dev/null
+++ b/libchrome/base/trace_event/trace_event_unittest.cc
@@ -0,0 +1,3184 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <math.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdlib>
+#include <memory>
+#include <utility>
+
+#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/macros.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/singleton.h"
+#include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/pattern.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_buffer.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 CancelTrace() {
+    WaitableEvent flush_complete_event(
+        WaitableEvent::ResetPolicy::AUTOMATIC,
+        WaitableEvent::InitialState::NOT_SIGNALED);
+    CancelTraceAsync(&flush_complete_event);
+    flush_complete_event.Wait();
+  }
+
+  void EndTraceAndFlush() {
+    num_flush_callbacks_ = 0;
+    WaitableEvent flush_complete_event(
+        WaitableEvent::ResetPolicy::AUTOMATIC,
+        WaitableEvent::InitialState::NOT_SIGNALED);
+    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(
+        WaitableEvent::ResetPolicy::AUTOMATIC,
+        WaitableEvent::InitialState::NOT_SIGNALED);
+    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 CancelTraceAsync(WaitableEvent* flush_complete_event) {
+    TraceLog::GetInstance()->CancelTracing(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+                   base::Unretained(flush_complete_event)));
+  }
+
+  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 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;
+    num_flush_callbacks_ = 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_;
+  size_t num_flush_callbacks_;
+
+ 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) {
+  num_flush_callbacks_++;
+  if (num_flush_callbacks_ > 1) {
+    EXPECT_FALSE(events_str->data().empty());
+  }
+  AutoLock lock(lock_);
+  json_output_.json_output.clear();
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment(events_str->data());
+  trace_buffer_.Finish();
+
+  std::unique_ptr<Value> root = base::JSONReader::Read(
+      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()) {
+    std::unique_ptr<Value> item;
+    root_list->Remove(0, &item);
+    trace_parsed_.Append(std::move(item));
+  }
+
+  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() {
+  std::unique_ptr<ListValue> old_trace_parsed(trace_parsed_.CreateDeepCopy());
+  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 = nullptr;
+    old_trace_parsed->Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY) {
+      trace_parsed_.Append(value->CreateDeepCopy());
+      continue;
+    }
+    DictionaryValue* dict = static_cast<DictionaryValue*>(value);
+    std::string tmp;
+    if (dict->GetString("ph", &tmp) && tmp == "M")
+      continue;
+
+    trace_parsed_.Append(value->CreateDeepCopy());
+  }
+}
+
+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_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_COUNTER1("all", "TRACE_COUNTER1 call", 31415);
+    TRACE_COUNTER2("all", "TRACE_COUNTER2 call",
+                   "a", 30000,
+                   "b", 1415);
+
+    TRACE_COUNTER_WITH_TIMESTAMP1("all", "TRACE_COUNTER_WITH_TIMESTAMP1 call",
+                                  42, 31415);
+    TRACE_COUNTER_WITH_TIMESTAMP2("all", "TRACE_COUNTER_WITH_TIMESTAMP2 call",
+                                  42, "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_EVENT_OBJECT_CREATED_WITH_ID(
+        "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42));
+    TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+        "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42), "hello");
+    TRACE_EVENT_OBJECT_DELETED_WITH_ID(
+        "all", "tracked object 3", TRACE_ID_WITH_SCOPE("scope", 0x42));
+
+    TRACE_EVENT1(kControlCharacters, kControlCharacters,
+                 kControlCharacters, kControlCharacters);
+
+    uint64_t context_id = 0x20151021;
+
+    TRACE_EVENT_ENTER_CONTEXT("all", "TRACE_EVENT_ENTER_CONTEXT call",
+                              TRACE_ID_WITH_SCOPE("scope", context_id));
+    TRACE_EVENT_LEAVE_CONTEXT("all", "TRACE_EVENT_LEAVE_CONTEXT call",
+                              TRACE_ID_WITH_SCOPE("scope", context_id));
+    TRACE_EVENT_SCOPED_CONTEXT("disabled-by-default-cat",
+                               "TRACE_EVENT_SCOPED_CONTEXT disabled call",
+                               context_id);
+    TRACE_EVENT_SCOPED_CONTEXT("all", "TRACE_EVENT_SCOPED_CONTEXT call",
+                               context_id);
+  }  // 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_("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_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_WITH_TIMESTAMP1 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);
+
+    int ts;
+    EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+    EXPECT_EQ(42, ts);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP2 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);
+
+    int ts;
+    EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+    EXPECT_EQ(42, ts);
+  }
+
+  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_FALSE((item && item->HasKey("scope")));
+    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_FALSE((item && item->HasKey("scope")));
+    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_FALSE((item && item->HasKey("scope")));
+    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_("tracked object 3");
+  {
+    std::string phase;
+    std::string scope;
+    std::string id;
+    std::string snapshot;
+
+    EXPECT_TRUE((item && item->GetString("ph", &phase)));
+    EXPECT_EQ("N", phase);
+    EXPECT_TRUE((item && item->GetString("scope", &scope)));
+    EXPECT_EQ("scope", scope);
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x42", id);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 3", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("O", phase);
+    EXPECT_TRUE((item && item->GetString("scope", &scope)));
+    EXPECT_EQ("scope", scope);
+    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 3", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("D", phase);
+    EXPECT_TRUE((item && item->GetString("scope", &scope)));
+    EXPECT_EQ("scope", scope);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x42", id);
+  }
+
+  EXPECT_FIND_(kControlCharacters);
+  EXPECT_SUB_FIND_(kControlCharacters);
+
+  EXPECT_FIND_("TRACE_EVENT_ENTER_CONTEXT call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("(", ph);
+
+    std::string scope;
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("scope", &scope)));
+    EXPECT_EQ("scope", scope);
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x20151021", id);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_LEAVE_CONTEXT call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ(")", ph);
+
+    std::string scope;
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("scope", &scope)));
+    EXPECT_EQ("scope", scope);
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x20151021", id);
+  }
+
+  std::vector<const DictionaryValue*> scoped_context_calls =
+      FindTraceEntries(trace_parsed, "TRACE_EVENT_SCOPED_CONTEXT call");
+  EXPECT_EQ(2u, scoped_context_calls.size());
+  {
+    item = scoped_context_calls[0];
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("(", ph);
+
+    std::string id;
+    EXPECT_FALSE((item && item->HasKey("scope")));
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x20151021", id);
+  }
+
+  {
+    item = scoped_context_calls[1];
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ(")", ph);
+
+    std::string id;
+    EXPECT_FALSE((item && item->HasKey("scope")));
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x20151021", id);
+  }
+}
+
+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]);
+    }
+  }
+}
+
+void CheckTraceDefaultCategoryFilters(const TraceLog& trace_log) {
+  // Default enables all category filters except the disabled-by-default-* ones.
+  EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("bar"));
+  EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled("foo,bar"));
+  EXPECT_TRUE(*trace_log.GetCategoryGroupEnabled(
+        "foo,disabled-by-default-foo"));
+  EXPECT_FALSE(*trace_log.GetCategoryGroupEnabled(
+        "disabled-by-default-foo,disabled-by-default-bar"));
+}
+
+}  // 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_);
+}
+
+// Emit some events and validate that only empty strings are received
+// if we tell Flush() to discard events.
+TEST_F(TraceEventTestFixture, DataDiscarded) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  TraceWithAllMacroVariants(NULL);
+
+  CancelTrace();
+
+  EXPECT_TRUE(trace_parsed_.empty());
+}
+
+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() {}
+  ~AfterStateChangeEnabledStateObserver() override {}
+
+  // 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() {}
+  ~SelfRemovingEnabledStateObserver() override {}
+
+  // 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_F(TraceEventTestFixture, TestTraceFlush) {
+  size_t min_traces = 1;
+  size_t max_traces = 1;
+  do {
+    max_traces *= 2;
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < max_traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+  } while (num_flush_callbacks_ < 2);
+
+  while (min_traces + 50 <  max_traces) {
+    size_t traces = (min_traces + max_traces) / 2;
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+    if (num_flush_callbacks_ < 2) {
+      min_traces = traces - 10;
+    } else {
+      max_traces = traces + 10;
+    }
+  }
+
+  for (size_t traces = min_traces; traces < max_traces; traces++) {
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(),
+                                        TraceLog::RECORDING_MODE);
+    for (size_t i = 0; i < traces; i++) {
+      TRACE_EVENT_INSTANT0("x", "y", TRACE_EVENT_SCOPE_THREAD);
+    }
+    EndTraceAndFlush();
+  }
+}
+
+TEST_F(TraceEventTestFixture, AddMetadataEvent) {
+  int num_calls = 0;
+
+  class Convertable : public ConvertableToTraceFormat {
+   public:
+    explicit Convertable(int* num_calls) : num_calls_(num_calls) {}
+    ~Convertable() override {}
+    void AppendAsTraceFormat(std::string* out) const override {
+      (*num_calls_)++;
+      out->append("\"metadata_value\"");
+    }
+
+   private:
+    int* num_calls_;
+  };
+
+  std::unique_ptr<ConvertableToTraceFormat> conv1(new Convertable(&num_calls));
+  std::unique_ptr<Convertable> conv2(new Convertable(&num_calls));
+
+  BeginTrace();
+  TRACE_EVENT_API_ADD_METADATA_EVENT(
+      TraceLog::GetCategoryGroupEnabled("__metadata"), "metadata_event_1",
+      "metadata_arg_name", std::move(conv1));
+  TRACE_EVENT_API_ADD_METADATA_EVENT(
+      TraceLog::GetCategoryGroupEnabled("__metadata"), "metadata_event_2",
+      "metadata_arg_name", std::move(conv2));
+  // |AppendAsTraceFormat| should only be called on flush, not when the event
+  // is added.
+  ASSERT_EQ(0, num_calls);
+  EndTraceAndFlush();
+  ASSERT_EQ(2, num_calls);
+  EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_1", "M",
+                                    "metadata_arg_name", "metadata_value"));
+  EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_2", "M",
+                                    "metadata_arg_name", "metadata_value"));
+
+  // The metadata event should only be adde to the current trace. In this new
+  // trace, the event should not appear.
+  BeginTrace();
+  EndTraceAndFlush();
+  ASSERT_EQ(2, num_calls);
+}
+
+// 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(ContainsValue(cat_groups, "c1"));
+  EXPECT_TRUE(ContainsValue(cat_groups, "c2"));
+  EXPECT_TRUE(ContainsValue(cat_groups, "c3"));
+  EXPECT_TRUE(ContainsValue(cat_groups, "c4"));
+  EXPECT_TRUE(ContainsValue(cat_groups, "c5,c6"));
+  EXPECT_TRUE(ContainsValue(cat_groups, "c7,c8"));
+  EXPECT_TRUE(ContainsValue(cat_groups, "disabled-by-default-c9"));
+  // Make sure metadata isn't returned.
+  EXPECT_FALSE(ContainsValue(cat_groups, "__metadata"));
+
+  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",
+            trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
+            0, trace_event_internal::kNoId,
+            "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",
+            trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
+            0, trace_event_internal::kNoId,
+            "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",
+            trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
+            0, trace_event_internal::kNoId,
+            "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",
+            trace_event_internal::kGlobalScope, trace_event_internal::kNoId,
+            0, trace_event_internal::kNoId,
+            "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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                    WaitableEvent::InitialState::NOT_SIGNALED);
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                          WaitableEvent::InitialState::NOT_SIGNALED);
+    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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                          WaitableEvent::InitialState::NOT_SIGNALED);
+    threads[i]->Start();
+    thread_ids[i] = threads[i]->GetThreadId();
+    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(
+    "",
+    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, TraceWithDefaultCategoryFilters) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+
+  trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
+  CheckTraceDefaultCategoryFilters(*trace_log);
+  trace_log->SetDisabled();
+
+  trace_log->SetEnabled(TraceConfig("", ""), TraceLog::RECORDING_MODE);
+  CheckTraceDefaultCategoryFilters(*trace_log);
+  trace_log->SetDisabled();
+
+  trace_log->SetEnabled(TraceConfig("*", ""), TraceLog::RECORDING_MODE);
+  CheckTraceDefaultCategoryFilters(*trace_log);
+  trace_log->SetDisabled();
+
+  trace_log->SetEnabled(TraceConfig(""), TraceLog::RECORDING_MODE);
+  CheckTraceDefaultCategoryFilters(*trace_log);
+  trace_log->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceWithDisabledByDefaultCategoryFilters) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+
+  trace_log->SetEnabled(TraceConfig("foo,disabled-by-default-foo", ""),
+                        TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-foo"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-bar"));
+  trace_log->SetDisabled();
+
+  // Enabling only the disabled-by-default-* category means the default ones
+  // are also enabled.
+  trace_log->SetEnabled(TraceConfig("disabled-by-default-foo", ""),
+                        TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-bar"));
+  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();
+}
+
+class MyData : public ConvertableToTraceFormat {
+ public:
+  MyData() {}
+  ~MyData() override {}
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append("{\"foo\":1}");
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MyData);
+};
+
+TEST_F(TraceEventTestFixture, ConvertableTypes) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  std::unique_ptr<ConvertableToTraceFormat> data(new MyData());
+  std::unique_ptr<ConvertableToTraceFormat> data1(new MyData());
+  std::unique_ptr<ConvertableToTraceFormat> data2(new MyData());
+  TRACE_EVENT1("foo", "bar", "data", std::move(data));
+  TRACE_EVENT2("foo", "baz", "data1", std::move(data1), "data2",
+               std::move(data2));
+
+  // Check that std::unique_ptr<DerivedClassOfConvertable> are properly treated
+  // as
+  // convertable and not accidentally casted to bool.
+  std::unique_ptr<MyData> convertData1(new MyData());
+  std::unique_ptr<MyData> convertData2(new MyData());
+  std::unique_ptr<MyData> convertData3(new MyData());
+  std::unique_ptr<MyData> convertData4(new MyData());
+  TRACE_EVENT2("foo", "string_first", "str", "string value 1", "convert",
+               std::move(convertData1));
+  TRACE_EVENT2("foo", "string_second", "convert", std::move(convertData2),
+               "str", "string value 2");
+  TRACE_EVENT2("foo", "both_conv", "convert1", std::move(convertData3),
+               "convert2", std::move(convertData4));
+  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);
+
+  dict = FindNamePhase("both_conv", "X");
+  ASSERT_TRUE(dict);
+
+  args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  value = NULL;
+  convertable_dict = NULL;
+  foo_val = 0;
+  EXPECT_TRUE(args_dict->Get("convert1", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+  EXPECT_TRUE(args_dict->Get("convert2", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+}
+
+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);
+}
+
+TEST_F(TraceEventTestFixture, NameIsEscaped) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT0("category", "name\\with\\backspaces");
+  EndTraceAndFlush();
+
+  EXPECT_TRUE(FindMatchingValue("cat", "category"));
+  EXPECT_TRUE(FindMatchingValue("name", "name\\with\\backspaces"));
+}
+
+namespace {
+
+bool IsArgNameWhitelisted(const char* arg_name) {
+  return base::MatchPattern(arg_name, "granular_arg_whitelisted");
+}
+
+bool IsTraceEventArgsWhitelisted(const char* category_group_name,
+                                 const char* event_name,
+                                 ArgumentNameFilterPredicate* arg_filter) {
+  if (base::MatchPattern(category_group_name, "toplevel") &&
+      base::MatchPattern(event_name, "*")) {
+    return true;
+  }
+
+  if (base::MatchPattern(category_group_name, "benchmark") &&
+      base::MatchPattern(event_name, "granularly_whitelisted")) {
+    *arg_filter = base::Bind(&IsArgNameWhitelisted);
+    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);
+
+  TRACE_EVENT2("benchmark", "granularly_whitelisted",
+               "granular_arg_whitelisted", "whitelisted_value",
+               "granular_arg_blacklisted", "blacklisted_value");
+
+  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__");
+
+  dict = FindNamePhase("granularly_whitelisted", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  EXPECT_TRUE(args_dict->GetString("granular_arg_whitelisted", &args_string));
+  EXPECT_EQ(args_string, "whitelisted_value");
+
+  EXPECT_TRUE(args_dict->GetString("granular_arg_blacklisted", &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<TimeTicks> collected_events_timestamps_;
+
+  static TraceEventCallbackTest* s_instance;
+  static void Callback(TimeTicks timestamp,
+                       char phase,
+                       const unsigned char* category_group_enabled,
+                       const char* name,
+                       const char* scope,
+                       unsigned long long id,
+                       int num_args,
+                       const char* const arg_names[],
+                       const unsigned char arg_types[],
+                       const unsigned long long arg_values[],
+                       unsigned int 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(
+      TraceBuffer::CreateTraceBufferVectorOfSize(100));
+  do {
+    TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
+        "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
+    TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
+        "all", "with_timestamp", 0, 0, TimeTicks::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_t last_seq = 0;
+  size_t chunk_index;
+  EXPECT_EQ(0u, buffer->Size());
+
+  std::unique_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, std::unique_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, std::unique_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, std::unique_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;
+  std::unique_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, std::unique_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());
+
+  std::unique_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, std::unique_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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                    WaitableEvent::InitialState::NOT_SIGNALED);
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                 WaitableEvent::InitialState::NOT_SIGNALED);
+  WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                WaitableEvent::InitialState::NOT_SIGNALED);
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                    WaitableEvent::InitialState::NOT_SIGNALED);
+  thread.Start();
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+
+  WaitableEvent task_start_event(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                 WaitableEvent::InitialState::NOT_SIGNALED);
+  WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                WaitableEvent::InitialState::NOT_SIGNALED);
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                    WaitableEvent::InitialState::NOT_SIGNALED);
+  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(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                 WaitableEvent::InitialState::NOT_SIGNALED);
+  WaitableEvent task_stop_event(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                WaitableEvent::InitialState::NOT_SIGNALED);
+  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 = TimeTicks::Now() - TimeTicks();
+  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, TimeTicks::Now().ToInternalValue());
+  TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
+      "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
+
+  EndTraceAndFlush();
+  DropTracedMetadataRecords();
+
+  double end_time = static_cast<double>(
+      (TimeTicks::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());
+}
+
+TEST_F(TraceEventTestFixture, ClockSyncEventsAreAlwaysAddedToTrace) {
+  BeginSpecificTrace("-*");
+  TRACE_EVENT_CLOCK_SYNC_RECEIVER(1);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindNamePhase("clock_sync", "c"));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_log.cc b/libchrome/base/trace_event/trace_log.cc
new file mode 100644
index 0000000..12cebc6
--- /dev/null
+++ b/libchrome/base/trace_event/trace_log.cc
@@ -0,0 +1,1801 @@
+// 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_log.h"
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <utility>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/leak_annotations.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/singleton.h"
+#include "base/process/process_metrics.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/worker_pool.h"
+#include "base/time/time.h"
+#include "base/trace_event/heap_profiler.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.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_buffer.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "base/trace_event/trace_sampling_thread.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/trace_event/trace_event_etw_export_win.h"
+#endif
+
+// The thread buckets for the sampling profiler.
+BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+namespace base {
+namespace internal {
+
+class DeleteTraceLogForTesting {
+ public:
+  static void Delete() {
+    Singleton<trace_event::TraceLog,
+              LeakySingletonTraits<trace_event::TraceLog>>::OnExit(0);
+  }
+};
+
+}  // namespace internal
+
+namespace trace_event {
+
+namespace {
+
+// 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;
+static_assert(
+    kTraceEventVectorBigBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
+    "Too many big buffer chunks");
+const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
+static_assert(
+    kTraceEventVectorBufferChunks <= TraceBufferChunk::kMaxChunkIndex,
+    "Too many vector buffer chunks");
+const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
+
+// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
+const size_t kEchoToConsoleTraceEventBufferChunks = 256;
+
+const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
+const int kThreadFlushTimeoutMs = 3000;
+
+#define MAX_CATEGORY_GROUPS 200
+
+// 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"};
+
+// 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_num_builtin_categories = 4;
+// 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();
+}
+
+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,
+      TimeTicks(),
+      ThreadTicks(),
+      TRACE_EVENT_PHASE_METADATA,
+      &g_category_group_enabled[g_category_metadata],
+      metadata_name,
+      trace_event_internal::kGlobalScope,  // scope
+      trace_event_internal::kNoId,  // id
+      trace_event_internal::kNoId,  // bind_id
+      num_args,
+      &arg_name,
+      &arg_type,
+      &arg_value,
+      nullptr,
+      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);
+};
+
+// Use this function instead of TraceEventHandle constructor to keep the
+// overhead of ScopedTracer (trace_event.h) constructor minimum.
+void MakeHandle(uint32_t chunk_seq,
+                size_t chunk_index,
+                size_t event_index,
+                TraceEventHandle* handle) {
+  DCHECK(chunk_seq);
+  DCHECK(chunk_index <= TraceBufferChunk::kMaxChunkIndex);
+  DCHECK(event_index < TraceBufferChunk::kTraceBufferChunkSize);
+  handle->chunk_seq = chunk_seq;
+  handle->chunk_index = static_cast<uint16_t>(chunk_index);
+  handle->event_index = static_cast<uint16_t>(event_index);
+}
+
+}  // namespace
+
+// 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);
+};
+
+class TraceLog::ThreadLocalEventBuffer
+    : public MessageLoop::DestructionObserver,
+      public MemoryDumpProvider {
+ public:
+  explicit ThreadLocalEventBuffer(TraceLog* trace_log);
+  ~ThreadLocalEventBuffer() override;
+
+  TraceEvent* AddTraceEvent(TraceEventHandle* handle);
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) {
+    if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
+        handle.chunk_index != chunk_index_) {
+      return nullptr;
+    }
+
+    return chunk_->GetEventAt(handle.event_index);
+  }
+
+  int generation() const { return generation_; }
+
+ private:
+  // MessageLoop::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override;
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(const MemoryDumpArgs& args,
+                    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_;
+  std::unique_ptr<TraceBufferChunk> chunk_;
+  size_t chunk_index_;
+  int generation_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer);
+};
+
+TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
+    : trace_log_(trace_log),
+      chunk_index_(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, "ThreadLocalEventBuffer", 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);
+
+  {
+    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::WillDestroyCurrentMessageLoop() {
+  delete this;
+}
+
+bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(const MemoryDumpArgs&,
+                                                    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_, std::move(chunk_));
+  }
+  // Otherwise this method may be called from the destructor, or TraceLog will
+  // find the generation mismatch and delete this buffer soon.
+}
+
+struct TraceLog::RegisteredAsyncObserver {
+  explicit RegisteredAsyncObserver(WeakPtr<AsyncEnabledStateObserver> observer)
+      : observer(observer), task_runner(ThreadTaskRunnerHandle::Get()) {}
+  ~RegisteredAsyncObserver() {}
+
+  WeakPtr<AsyncEnabledStateObserver> observer;
+  scoped_refptr<SequencedTaskRunner> task_runner;
+};
+
+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()));
+#endif
+
+  logged_events_.reset(CreateTraceBuffer());
+
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(this, "TraceLog",
+                                                         nullptr);
+}
+
+TraceLog::~TraceLog() {}
+
+void TraceLog::InitializeThreadLocalEventBufferIfSupported() {
+  // 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())
+    return;
+  HEAP_PROFILER_SCOPED_IGNORE;
+  auto* 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);
+  }
+}
+
+bool TraceLog::OnMemoryDump(const MemoryDumpArgs&, ProcessMemoryDump* pmd) {
+  // TODO(ssid): Use MemoryDumpArgs to create light dumps when requested
+  // (crbug.com/499731).
+  TraceEventMemoryOverhead overhead;
+  overhead.Add("TraceLog", sizeof(*this));
+  {
+    AutoLock lock(lock_);
+    if (logged_events_)
+      logged_events_->EstimateTraceMemoryOverhead(&overhead);
+
+    for (auto& metadata_event : metadata_events_)
+      metadata_event->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;
+  }
+
+  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::IsCategoryGroupEnabled(
+          category_group)) {
+    enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+  }
+#endif
+
+  // TODO(primiano): this is a temporary workaround for catapult:#2341,
+  // to guarantee that metadata events are always added even if the category
+  // filter is "-*". See crbug.com/618054 for more details and long-term fix.
+  if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata"))
+    enabled_flag |= ENABLED_FOR_RECORDING;
+
+  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_t>(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_);
+  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;
+  std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver> observer_map;
+  {
+    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_;
+    observer_map = async_observers_;
+  }
+  // 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();
+  for (const auto& it : observer_map) {
+    it.second.task_runner->PostTask(
+        FROM_HERE, Bind(&AsyncEnabledStateObserver::OnTraceLogEnabled,
+                        it.second.observer));
+  }
+
+  {
+    AutoLock lock(lock_);
+    dispatching_to_observer_list_ = false;
+  }
+}
+
+void TraceLog::SetArgumentFilterPredicate(
+    const 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();
+
+  // Remove metadata events so they will not get added to a subsequent trace.
+  metadata_events_.clear();
+
+  dispatching_to_observer_list_ = true;
+  std::vector<EnabledStateObserver*> observer_list =
+      enabled_state_observer_list_;
+  std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver> observer_map =
+      async_observers_;
+
+  {
+    // 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();
+    for (const auto& it : observer_map) {
+      it.second.task_runner->PostTask(
+          FROM_HERE, Bind(&AsyncEnabledStateObserver::OnTraceLogDisabled,
+                          it.second.observer));
+    }
+  }
+  dispatching_to_observer_list_ = false;
+}
+
+int TraceLog::GetNumTracesRecorded() {
+  AutoLock lock(lock_);
+  if (!IsEnabled())
+    return -1;
+  return num_traces_recorded_;
+}
+
+void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) {
+  AutoLock lock(lock_);
+  enabled_state_observer_list_.push_back(listener);
+}
+
+void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
+  AutoLock lock(lock_);
+  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 {
+  AutoLock lock(lock_);
+  return ContainsValue(enabled_state_observer_list_, listener);
+}
+
+TraceLogStatus TraceLog::GetStatus() const {
+  AutoLock lock(lock_);
+  TraceLogStatus result;
+  result.event_capacity = static_cast<uint32_t>(logged_events_->Capacity());
+  result.event_count = static_cast<uint32_t>(logged_events_->Size());
+  return result;
+}
+
+bool TraceLog::BufferIsFull() const {
+  AutoLock lock(lock_);
+  return logged_events_->IsFull();
+}
+
+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_,
+                                std::move(thread_shared_chunk_));
+  }
+
+  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) {
+  FlushInternal(cb, use_worker_thread, false);
+}
+
+void TraceLog::CancelTracing(const OutputCallback& cb) {
+  SetDisabled();
+  FlushInternal(cb, false, true);
+}
+
+void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
+                             bool use_worker_thread,
+                             bool discard_events) {
+  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(thread_message_loops_.empty() || flush_task_runner_);
+    flush_output_callback_ = cb;
+
+    if (thread_shared_chunk_) {
+      logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                  std::move(thread_shared_chunk_));
+    }
+
+    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, discard_events));
+    }
+    flush_task_runner_->PostDelayedTask(
+        FROM_HERE, Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation,
+                        discard_events),
+        TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
+    return;
+  }
+
+  FinishFlush(generation, discard_events);
+}
+
+// Usually it runs on a different thread.
+void TraceLog::ConvertTraceEventsToTraceFormat(
+    std::unique_ptr<TraceBuffer> logged_events,
+    const OutputCallback& flush_output_callback,
+    const ArgumentFilterPredicate& argument_filter_predicate) {
+  if (flush_output_callback.is_null())
+    return;
+
+  HEAP_PROFILER_SCOPED_IGNORE;
+  // The callback need to be called at least once even if there is no events
+  // to let the caller know the completion of flush.
+  scoped_refptr<RefCountedString> json_events_str_ptr = new RefCountedString();
+  while (const TraceBufferChunk* chunk = logged_events->NextChunk()) {
+    for (size_t j = 0; j < chunk->size(); ++j) {
+      size_t size = json_events_str_ptr->size();
+      if (size > kTraceEventBufferSizeInBytes) {
+        flush_output_callback.Run(json_events_str_ptr, true);
+        json_events_str_ptr = new RefCountedString();
+      } else if (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, false);
+}
+
+void TraceLog::FinishFlush(int generation, bool discard_events) {
+  std::unique_ptr<TraceBuffer> previous_logged_events;
+  OutputCallback flush_output_callback;
+  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 (discard_events) {
+    if (!flush_output_callback.is_null()) {
+      scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+      flush_output_callback.Run(empty_result, false);
+    }
+    return;
+  }
+
+  if (use_worker_thread_ &&
+      WorkerPool::PostTask(
+          FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+                          Passed(&previous_logged_events),
+                          flush_output_callback, argument_filter_predicate),
+          true)) {
+    return;
+  }
+
+  ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
+                                  flush_output_callback,
+                                  argument_filter_predicate);
+}
+
+// Run in each thread holding a local event buffer.
+void TraceLog::FlushCurrentThread(int generation, bool discard_events) {
+  {
+    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,
+                      discard_events));
+}
+
+void TraceLog::OnFlushTimeout(int generation, bool discard_events) {
+  {
+    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)->GetThreadName();
+    }
+  }
+  FinishFlush(generation, discard_events);
+}
+
+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,
+    const char* scope,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      scope,
+      id,
+      trace_event_internal::kNoId,  // bind_id
+      thread_id,
+      now,
+      num_args,
+      arg_names,
+      arg_types,
+      arg_values,
+      convertable_values,
+      flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithBindId(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned long long bind_id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      scope,
+      id,
+      bind_id,
+      thread_id,
+      now,
+      num_args,
+      arg_names,
+      arg_types,
+      arg_values,
+      convertable_values,
+      flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithProcessId(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int process_id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  base::TimeTicks now = base::TimeTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      scope,
+      id,
+      trace_event_internal::kNoId,  // bind_id
+      process_id,
+      now,
+      num_args,
+      arg_names,
+      arg_types,
+      arg_values,
+      convertable_values,
+      flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
+}
+
+// Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp
+// with kNoId as bind_id
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const TimeTicks& timestamp,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase,
+      category_group_enabled,
+      name,
+      scope,
+      id,
+      trace_event_internal::kNoId,  // bind_id
+      thread_id,
+      timestamp,
+      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,
+    const char* scope,
+    unsigned long long id,
+    unsigned long long bind_id,
+    int thread_id,
+    const TimeTicks& timestamp,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int 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) {
+    if ((flags & TRACE_EVENT_FLAG_FLOW_IN) ||
+        (flags & TRACE_EVENT_FLAG_FLOW_OUT))
+      bind_id = MangleEventId(bind_id);
+    id = MangleEventId(id);
+  }
+
+  TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
+  ThreadTicks thread_now = ThreadNow();
+
+  // |thread_local_event_buffer_| can be null if the current thread doesn't have
+  // a message loop or the message loop is blocked.
+  InitializeThreadLocalEventBufferIfSupported();
+  auto* thread_local_event_buffer = thread_local_event_buffer_.Get();
+
+  // 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 = base::SplitStringPiece(
+            existing_name->second, ",", base::KEEP_WHITESPACE,
+            base::SPLIT_WANT_NONEMPTY);
+        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) {
+    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,
+                              scope,
+                              id,
+                              bind_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, scope, id, num_args, arg_names,
+          arg_types, arg_values, flags);
+    }
+  }
+
+  // TODO(primiano): Add support for events with copied name crbug.com/581078
+  if (!(flags & TRACE_EVENT_FLAG_COPY)) {
+    if (AllocationContextTracker::capture_mode() ==
+        AllocationContextTracker::CaptureMode::PSEUDO_STACK) {
+      if (phase == TRACE_EVENT_PHASE_BEGIN ||
+          phase == TRACE_EVENT_PHASE_COMPLETE) {
+        AllocationContextTracker::GetInstanceForCurrentThread()
+            ->PushPseudoStackFrame(name);
+      } else if (phase == TRACE_EVENT_PHASE_END) {
+        // The pop for |TRACE_EVENT_PHASE_COMPLETE| events
+        // is in |TraceLog::UpdateTraceEventDuration|.
+        AllocationContextTracker::GetInstanceForCurrentThread()
+            ->PopPseudoStackFrame(name);
+      }
+    }
+  }
+
+  return handle;
+}
+
+void TraceLog::AddMetadataEvent(
+    const unsigned char* category_group_enabled,
+    const char* name,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned int flags) {
+  HEAP_PROFILER_SCOPED_IGNORE;
+  std::unique_ptr<TraceEvent> trace_event(new TraceEvent);
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  ThreadTicks thread_now = ThreadNow();
+  TimeTicks now = OffsetNow();
+  AutoLock lock(lock_);
+  trace_event->Initialize(
+      thread_id, now, thread_now, TRACE_EVENT_PHASE_METADATA,
+      category_group_enabled, name,
+      trace_event_internal::kGlobalScope,  // scope
+      trace_event_internal::kNoId,         // id
+      trace_event_internal::kNoId,         // bind_id
+      num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+  metadata_events_.push_back(std::move(trace_event));
+}
+
+// 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 TimeTicks& timestamp,
+                                            TraceEvent* trace_event) {
+  HEAP_PROFILER_SCOPED_IGNORE;
+  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::UpdateTraceEventDuration(
+    const unsigned char* category_group_enabled,
+    const char* name,
+    TraceEventHandle handle) {
+  char category_group_enabled_local = *category_group_enabled;
+  if (!category_group_enabled_local)
+    return;
+
+  // 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();
+  TimeTicks now = OffsetNow();
+
+#if defined(OS_WIN)
+  // Generate an ETW event that marks the end of a complete event.
+  if (category_group_enabled_local & ENABLED_FOR_ETW_EXPORT)
+    TraceEventETWExport::AddCompleteEndEvent(name);
+#endif  // OS_WIN
+
+  std::string console_message;
+  if (category_group_enabled_local & 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 (AllocationContextTracker::capture_mode() ==
+        AllocationContextTracker::CaptureMode::PSEUDO_STACK) {
+      // The corresponding push is in |AddTraceEventWithThreadIdAndTimestamp|.
+      AllocationContextTracker::GetInstanceForCurrentThread()
+          ->PopPseudoStackFrame(name);
+    }
+  }
+
+  if (console_message.size())
+    LOG(ERROR) << console_message;
+
+  if (category_group_enabled_local & 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::kGlobalScope, trace_event_internal::kNoId, 0,
+        nullptr, nullptr, nullptr, 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_t TraceLog::MangleEventId(uint64_t id) {
+  return id ^ process_id_hash_;
+}
+
+void TraceLog::AddMetadataEventsWhileLocked() {
+  lock_.AssertAcquired();
+
+  // Move metadata added by |AddMetadataEvent| into the trace log.
+  while (!metadata_events_.empty()) {
+    TraceEvent* event = AddEventToThreadSharedChunkWhileLocked(nullptr, false);
+    event->MoveFrom(std::move(metadata_events_.back()));
+    metadata_events_.pop_back();
+  }
+
+#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",
+                            base::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() {
+  internal::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();
+  }
+}
+
+TraceBuffer* TraceLog::CreateTraceBuffer() {
+  HEAP_PROFILER_SCOPED_IGNORE;
+  InternalTraceOptions options = trace_options();
+  if (options & kInternalRecordContinuously)
+    return TraceBuffer::CreateTraceBufferRingBuffer(
+        kTraceEventRingBufferChunks);
+  else if (options & kInternalEchoToConsole)
+    return TraceBuffer::CreateTraceBufferRingBuffer(
+        kEchoToConsoleTraceEventBufferChunks);
+  else if (options & kInternalRecordAsMuchAsPossible)
+    return TraceBuffer::CreateTraceBufferVectorOfSize(
+        kTraceEventVectorBigBufferChunks);
+  return TraceBuffer::CreateTraceBufferVectorOfSize(
+      kTraceEventVectorBufferChunks);
+}
+
+#if defined(OS_WIN)
+void TraceLog::UpdateETWCategoryGroupEnabledFlags() {
+  AutoLock lock(lock_);
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  // Go through each category and set/clear the ETW bit depending on whether the
+  // category is enabled.
+  for (size_t i = 0; i < category_index; i++) {
+    const char* category_group = g_category_groups[i];
+    DCHECK(category_group);
+    if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled(
+            category_group)) {
+      g_category_group_enabled[i] |= ENABLED_FOR_ETW_EXPORT;
+    } else {
+      g_category_group_enabled[i] &= ~ENABLED_FOR_ETW_EXPORT;
+    }
+  }
+}
+#endif  // defined(OS_WIN)
+
+void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
+}
+
+void TraceLog::AddAsyncEnabledStateObserver(
+    WeakPtr<AsyncEnabledStateObserver> listener) {
+  AutoLock lock(lock_);
+  async_observers_.insert(
+      std::make_pair(listener.get(), RegisteredAsyncObserver(listener)));
+}
+
+void TraceLog::RemoveAsyncEnabledStateObserver(
+    AsyncEnabledStateObserver* listener) {
+  AutoLock lock(lock_);
+  async_observers_.erase(listener);
+}
+
+bool TraceLog::HasAsyncEnabledStateObserver(
+    AsyncEnabledStateObserver* listener) const {
+  AutoLock lock(lock_);
+  return ContainsKey(async_observers_, listener);
+}
+
+}  // 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::kGlobalScope,  // scope
+            trace_event_internal::kNoId,  // id
+            static_cast<int>(base::PlatformThread::CurrentId()),  // thread_id
+            base::TimeTicks::Now(),
+            trace_event_internal::kZeroNumArgs,
+            nullptr,
+            nullptr,
+            nullptr,
+            nullptr,
+            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/libchrome/base/trace_event/trace_log.h b/libchrome/base/trace_event/trace_log.h
new file mode 100644
index 0000000..e4407e8
--- /dev/null
+++ b/libchrome/base/trace_event/trace_log.h
@@ -0,0 +1,531 @@
+// 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_LOG_H_
+#define BASE_TRACE_EVENT_TRACE_LOG_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "build/build_config.h"
+
+namespace base {
+
+template <typename Type>
+struct DefaultSingletonTraits;
+class RefCountedString;
+
+namespace trace_event {
+
+class TraceBuffer;
+class TraceBufferChunk;
+class TraceEvent;
+class TraceEventMemoryOverhead;
+class TraceSamplingThread;
+
+struct BASE_EXPORT TraceLogStatus {
+  TraceLogStatus();
+  ~TraceLogStatus();
+  uint32_t event_capacity;
+  uint32_t event_count;
+};
+
+class BASE_EXPORT TraceLog : public MemoryDumpProvider {
+ public:
+  enum Mode {
+    DISABLED = 0,
+    RECORDING_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 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;
+
+  // Initializes the thread-local event buffer, if not already initialized and
+  // if the current thread supports that (has a message loop).
+  void InitializeThreadLocalEventBufferIfSupported();
+
+  // 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:
+    virtual ~EnabledStateObserver() = default;
+
+    // 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;
+
+  // Asynchronous enabled state listeners. When tracing is enabled or disabled,
+  // for each observer, a task for invoking its appropriate callback is posted
+  // to the thread from which AddAsyncEnabledStateObserver() was called. This
+  // allows the observer to be safely destroyed, provided that it happens on the
+  // same thread that invoked AddAsyncEnabledStateObserver().
+  class BASE_EXPORT AsyncEnabledStateObserver {
+   public:
+    virtual ~AsyncEnabledStateObserver() = default;
+
+    // Posted just after the tracing system becomes enabled, outside |lock_|.
+    // TraceLog::IsEnabled() is true at this point.
+    virtual void OnTraceLogEnabled() = 0;
+
+    // Posted just after the tracing system becomes disabled, outside |lock_|.
+    // TraceLog::IsEnabled() is false at this point.
+    virtual void OnTraceLogDisabled() = 0;
+  };
+  void AddAsyncEnabledStateObserver(
+      WeakPtr<AsyncEnabledStateObserver> listener);
+  void RemoveAsyncEnabledStateObserver(AsyncEnabledStateObserver* listener);
+  bool HasAsyncEnabledStateObserver(AsyncEnabledStateObserver* 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)(TimeTicks timestamp,
+                                char phase,
+                                const unsigned char* category_group_enabled,
+                                const char* name,
+                                const char* scope,
+                                unsigned long long id,
+                                int num_args,
+                                const char* const arg_names[],
+                                const unsigned char arg_types[],
+                                const unsigned long long arg_values[],
+                                unsigned int flags);
+
+  // Enable tracing for EventCallback.
+  void SetEventCallbackEnabled(const TraceConfig& trace_config,
+                               EventCallback cb);
+  void SetEventCallbackDisabled();
+  void SetArgumentFilterPredicate(
+      const 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);
+
+  // Cancels tracing and discards collected data.
+  void CancelTracing(const OutputCallback& cb);
+
+  // 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,
+      const char* scope,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithBindId(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      unsigned long long bind_id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithProcessId(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      int process_id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      int thread_id,
+      const TimeTicks& timestamp,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      unsigned long long bind_id,
+      int thread_id,
+      const TimeTicks& timestamp,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+
+  // Adds a metadata event that will be written when the trace log is flushed.
+  void AddMetadataEvent(
+      const unsigned char* category_group_enabled,
+      const char* name,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned int flags);
+
+  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_t MangleEventId(uint64_t 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 thread_id, int sort_index);
+
+  // Allow setting an offset between the current TimeTicks 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();
+
+#if defined(OS_WIN)
+  // This function is called by the ETW exporting module whenever the ETW
+  // keyword (flags) changes. This keyword indicates which categories should be
+  // exported, so whenever it changes, we adjust accordingly.
+  void UpdateETWCategoryGroupEnabledFlags();
+#endif
+
+ 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(const MemoryDumpArgs& args,
+                    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;
+  struct RegisteredAsyncObserver;
+
+  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();
+
+  std::string EventToConsoleMessage(unsigned char phase,
+                                    const TimeTicks& timestamp,
+                                    TraceEvent* trace_event);
+
+  TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
+                                                     bool check_buffer_is_full);
+  void CheckIfBufferIsFullWhileLocked();
+  void SetDisabledWhileLocked();
+
+  TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
+                                       OptionalAutoLock* lock);
+
+  void FlushInternal(const OutputCallback& cb,
+                     bool use_worker_thread,
+                     bool discard_events);
+
+  // |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, bool discard_events);
+  // Usually it runs on a different thread.
+  static void ConvertTraceEventsToTraceFormat(
+      std::unique_ptr<TraceBuffer> logged_events,
+      const TraceLog::OutputCallback& flush_output_callback,
+      const ArgumentFilterPredicate& argument_filter_predicate);
+  void FinishFlush(int generation, bool discard_events);
+  void OnFlushTimeout(int generation, bool discard_events);
+
+  int generation() const {
+    return static_cast<int>(subtle::NoBarrier_Load(&generation_));
+  }
+  bool CheckGeneration(int generation) const {
+    return generation == this->generation();
+  }
+  void UseNextTraceBuffer();
+
+  TimeTicks OffsetNow() const { return OffsetTimestamp(TimeTicks::Now()); }
+  TimeTicks OffsetTimestamp(const TimeTicks& 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_;
+  std::unique_ptr<TraceBuffer> logged_events_;
+  std::vector<std::unique_ptr<TraceEvent>> metadata_events_;
+  subtle::AtomicWord /* EventCallback */ event_callback_;
+  bool dispatching_to_observer_list_;
+  std::vector<EnabledStateObserver*> enabled_state_observer_list_;
+  std::map<AsyncEnabledStateObserver*, RegisteredAsyncObserver>
+      async_observers_;
+
+  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<TimeTicks>> thread_event_start_times_;
+  base::hash_map<std::string, int> thread_colors_;
+
+  TimeTicks 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.
+  std::unique_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.
+  std::unique_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_;
+  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_LOG_H_
diff --git a/libchrome/base/trace_event/trace_log_constants.cc b/libchrome/base/trace_event/trace_log_constants.cc
new file mode 100644
index 0000000..cd2ff0d
--- /dev/null
+++ b/libchrome/base/trace_event/trace_log_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_log.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/libchrome/base/trace_event/trace_sampling_thread.cc b/libchrome/base/trace_event/trace_sampling_thread.cc
new file mode 100644
index 0000000..5a0d2f8
--- /dev/null
+++ b/libchrome/base/trace_event/trace_sampling_thread.cc
@@ -0,0 +1,107 @@
+// 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 <stddef.h>
+
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_log.h"
+#include "base/trace_event/trace_sampling_thread.h"
+
+namespace base {
+namespace trace_event {
+
+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;
+};
+
+TraceSamplingThread::TraceSamplingThread()
+    : thread_running_(false),
+      waitable_event_for_testing_(WaitableEvent::ResetPolicy::AUTOMATIC,
+                                  WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+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,
+      trace_event_internal::kGlobalScope, trace_event_internal::kNoId, 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() {}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/libchrome/base/trace_event/trace_sampling_thread.h b/libchrome/base/trace_event/trace_sampling_thread.h
new file mode 100644
index 0000000..f976a80
--- /dev/null
+++ b/libchrome/base/trace_event/trace_sampling_thread.h
@@ -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.
+
+#ifndef BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+#define BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
+
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceBucketData;
+typedef base::Callback<void(TraceBucketData*)> TraceSampleCallback;
+
+// 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* bucket_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_;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_SAMPLING_THREAD_H_
diff --git a/libchrome/base/tracked_objects.cc b/libchrome/base/tracked_objects.cc
new file mode 100644
index 0000000..487fd19
--- /dev/null
+++ b/libchrome/base/tracked_objects.cc
@@ -0,0 +1,980 @@
+// Copyright (c) 2012 The Chromium Authors. All 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/strings/stringprintf.h"
+#include "base/third_party/valgrind/memcheck.h"
+#include "base/threading/worker_pool.h"
+#include "base/tracking_info.h"
+#include "build/build_config.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;
+
+// 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_t>(assign_it))
+
+void DeathData::RecordDeath(const int32_t queue_duration,
+                            const int32_t run_duration,
+                            const uint32_t random_number) {
+  // We'll just clamp at INT_MAX, but we should note this in the UI as such.
+  if (count_ < INT_MAX)
+    base::subtle::NoBarrier_Store(&count_, count_ + 1);
+
+  int sample_probability_count =
+      base::subtle::NoBarrier_Load(&sample_probability_count_);
+  if (sample_probability_count < INT_MAX)
+    ++sample_probability_count;
+  base::subtle::NoBarrier_Store(&sample_probability_count_,
+                                sample_probability_count);
+
+  base::subtle::NoBarrier_Store(&queue_duration_sum_,
+                                queue_duration_sum_ + queue_duration);
+  base::subtle::NoBarrier_Store(&run_duration_sum_,
+                                run_duration_sum_ + run_duration);
+
+  if (queue_duration_max() < queue_duration)
+    base::subtle::NoBarrier_Store(&queue_duration_max_, queue_duration);
+  if (run_duration_max() < run_duration)
+    base::subtle::NoBarrier_Store(&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)) {
+    base::subtle::NoBarrier_Store(&queue_duration_sample_, queue_duration);
+    base::subtle::NoBarrier_Store(&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. These fields are updated using atomics. However, race
+  // conditions are possible since these are updated individually and not
+  // together atomically, resulting in the values being mutually inconsistent.
+  // The damage is limited to selecting a wrong sample, which is not something
+  // that can cause accumulating or cascading effects.
+  // If there were no inconsistencies 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.
+  base::subtle::NoBarrier_Store(&sample_probability_count_, 0);
+  base::subtle::NoBarrier_Store(&run_duration_max_, 0);
+  base::subtle::NoBarrier_Store(&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_t run_duration_sum,
+                                     int32_t run_duration_max,
+                                     int32_t run_duration_sample,
+                                     int32_t queue_duration_sum,
+                                     int32_t queue_duration_max,
+                                     int32_t 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
+ThreadData::NowFunction* ThreadData::now_function_for_testing_ = NULL;
+
+// 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
+base::subtle::Atomic32 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_t>(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) {
+  if (base::WorkerPool::RunsTasksOnCurrentThread())
+    return;
+  EnsureTlsInitialization();
+  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_t queue_duration,
+                             const TaskStopwatch& stopwatch) {
+  int32_t run_duration = stopwatch.RunDurationMs();
+
+  // Stir in some randomness, plus add constant in case durations are zero.
+  const uint32_t 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_t>(&births - reinterpret_cast<Births*>(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_t 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_t 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_t 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);
+  }
+}
+
+void ThreadData::EnsureTlsInitialization() {
+  if (base::subtle::Acquire_Load(&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 (base::subtle::Acquire_Load(&status_) >= DEACTIVATED)
+    return;  // Someone raced in here and beat us.
+
+  // Perform the "real" TLS initialization now, and leave it intact through
+  // process termination.
+  if (!tls_index_.initialized()) {  // Testing may have initialized this.
+    DCHECK_EQ(base::subtle::NoBarrier_Load(&status_), UNINITIALIZED);
+    tls_index_.Initialize(&ThreadData::OnThreadTermination);
+    DCHECK(tls_index_.initialized());
+  } else {
+    // TLS was initialzed for us earlier.
+    DCHECK_EQ(base::subtle::NoBarrier_Load(&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.
+  base::subtle::Release_Store(&status_, kInitialStartupState);
+  DCHECK(base::subtle::NoBarrier_Load(&status_) != UNINITIALIZED);
+}
+
+// static
+void ThreadData::InitializeAndSetTrackingStatus(Status status) {
+  DCHECK_GE(status, DEACTIVATED);
+  DCHECK_LE(status, PROFILING_ACTIVE);
+
+  EnsureTlsInitialization();  // No-op if already initialized.
+
+  if (status > DEACTIVATED)
+    status = PROFILING_ACTIVE;
+  base::subtle::Release_Store(&status_, status);
+}
+
+// static
+ThreadData::Status ThreadData::status() {
+  return static_cast<ThreadData::Status>(base::subtle::Acquire_Load(&status_));
+}
+
+// static
+bool ThreadData::TrackingStatus() {
+  return base::subtle::Acquire_Load(&status_) > DEACTIVATED;
+}
+
+// static
+void ThreadData::EnableProfilerTiming() {
+  base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, ENABLED_TIMING);
+}
+
+// static
+TrackedTime ThreadData::Now() {
+  if (now_function_for_testing_)
+    return TrackedTime::FromMilliseconds((*now_function_for_testing_)());
+  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);
+  // Almost UNINITIALIZED.
+  base::subtle::Release_Store(&status_, DORMANT_DURING_TESTS);
+
+  // 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_t 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_t run_duration_sum,
+    int32_t run_duration_max,
+    int32_t run_duration_sample,
+    int32_t queue_duration_sum,
+    int32_t queue_duration_max,
+    int32_t 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(
+    const ProcessDataPhaseSnapshot& other) = default;
+
+ProcessDataPhaseSnapshot::~ProcessDataPhaseSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ProcessDataPhaseSnapshot
+
+ProcessDataSnapshot::ProcessDataSnapshot()
+#if !defined(OS_NACL)
+    : process_id(base::GetCurrentProcId()) {
+#else
+    : process_id(base::kNullProcessId) {
+#endif
+}
+
+ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) =
+    default;
+
+ProcessDataSnapshot::~ProcessDataSnapshot() {
+}
+
+}  // namespace tracked_objects
diff --git a/libchrome/base/tracked_objects.h b/libchrome/base/tracked_objects.h
new file mode 100644
index 0000000..7ef0317
--- /dev/null
+++ b/libchrome/base/tracked_objects.h
@@ -0,0 +1,820 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stdint.h>
+
+#include <map>
+#include <set>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/process/process_handle.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 task runner 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_t run_duration_sum,
+                    int32_t run_duration_max,
+                    int32_t run_duration_sample,
+                    int32_t queue_duration_sum,
+                    int32_t queue_duration_max,
+                    int32_t 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_t run_duration_sum;
+  int32_t run_duration_max;
+  int32_t run_duration_sample;
+  int32_t queue_duration_sum;
+  int32_t queue_duration_max;
+  int32_t 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_t run_duration_sum,
+                         int32_t run_duration_max,
+                         int32_t run_duration_sample,
+                         int32_t queue_duration_sum,
+                         int32_t queue_duration_max,
+                         int32_t 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_t queue_duration,
+                   const int32_t run_duration,
+                   const uint32_t random_number);
+
+  // Metrics and past snapshots accessors, used only for serialization and in
+  // tests.
+  int count() const { return base::subtle::NoBarrier_Load(&count_); }
+  int32_t run_duration_sum() const {
+    return base::subtle::NoBarrier_Load(&run_duration_sum_);
+  }
+  int32_t run_duration_max() const {
+    return base::subtle::NoBarrier_Load(&run_duration_max_);
+  }
+  int32_t run_duration_sample() const {
+    return base::subtle::NoBarrier_Load(&run_duration_sample_);
+  }
+  int32_t queue_duration_sum() const {
+    return base::subtle::NoBarrier_Load(&queue_duration_sum_);
+  }
+  int32_t queue_duration_max() const {
+    return base::subtle::NoBarrier_Load(&queue_duration_max_);
+  }
+  int32_t queue_duration_sample() const {
+    return base::subtle::NoBarrier_Load(&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.
+  base::subtle::Atomic32 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.
+  base::subtle::Atomic32 sample_probability_count_;
+
+  // Basic tallies, used to compute averages.  Can be incremented only on the
+  // death thread.
+  base::subtle::Atomic32 run_duration_sum_;
+  base::subtle::Atomic32 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.
+  base::subtle::Atomic32 run_duration_max_;
+  base::subtle::Atomic32 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.
+  base::subtle::Atomic32 run_duration_sample_;
+  base::subtle::Atomic32 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 EnsureTlsInitialization();
+
+  // 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();
+
+  // 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);
+
+  // Type for an alternate timer function (testing only).
+  typedef unsigned int NowFunction();
+
+  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_t 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_for_testing_;
+
+  // 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 base::subtle::Atomic32 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_t 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_t 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_t 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_t 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(const ProcessDataPhaseSnapshot& other);
+  ~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(const ProcessDataSnapshot& other);
+  ~ProcessDataSnapshot();
+
+  PhasedProcessDataSnapshotMap phased_snapshots;
+  base::ProcessId process_id;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_TRACKED_OBJECTS_H_
diff --git a/libchrome/base/tracked_objects_unittest.cc b/libchrome/base/tracked_objects_unittest.cc
new file mode 100644
index 0000000..70d9601
--- /dev/null
+++ b/libchrome/base/tracked_objects_unittest.cc
@@ -0,0 +1,1187 @@
+// Copyright (c) 2012 The Chromium 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 <stdint.h>
+
+#include <memory>
+
+#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::now_function_for_testing_ = &TrackedObjectsTest::GetTestTime;
+  }
+
+  ~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_t 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_t 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);
+
+  std::unique_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, nullptr);
+  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_t run_ms = 42;
+  int32_t 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);
+
+  std::unique_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, nullptr);
+
+  int32_t run_ms = 42;
+  int32_t 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_t run_ms1 = 21;
+  int32_t 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/libchrome/base/tracking_info.cc b/libchrome/base/tracking_info.cc
new file mode 100644
index 0000000..c02b2f4
--- /dev/null
+++ b/libchrome/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/libchrome/base/tracking_info.h b/libchrome/base/tracking_info.h
new file mode 100644
index 0000000..6c3bcd1
--- /dev/null
+++ b/libchrome/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/libchrome/base/tuple.h b/libchrome/base/tuple.h
new file mode 100644
index 0000000..e82f2e5
--- /dev/null
+++ b/libchrome/base/tuple.h
@@ -0,0 +1,195 @@
+// 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.
+
+// Use std::tuple as tuple type. This file contains helper functions for
+// working with std::tuples.
+// The functions DispatchToMethod and DispatchToFunction take a function pointer
+// or instance and method pointer, and unpack a tuple into arguments to the
+// call.
+//
+// Example usage:
+//   // These two methods of creating a Tuple are identical.
+//   std::tuple<int, const char*> tuple_a(1, "wee");
+//   std::tuple<int, const char*> tuple_b = std::make_tuple(1, "wee");
+//
+//   void SomeFunc(int a, const char* b) { }
+//   DispatchToFunction(&SomeFunc, tuple_a);  // SomeFunc(1, "wee")
+//   DispatchToFunction(
+//       &SomeFunc, std::make_tuple(10, "foo"));    // SomeFunc(10, "foo")
+//
+//   struct { void SomeMeth(int a, int b, int c) { } } foo;
+//   DispatchToMethod(&foo, &Foo::SomeMeth, std::make_tuple(1, 2, 3));
+//   // foo->SomeMeth(1, 2, 3);
+
+#ifndef BASE_TUPLE_H_
+#define BASE_TUPLE_H_
+
+#include <stddef.h>
+#include <tuple>
+
+#include "base/bind_helpers.h"
+#include "build/build_config.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(OS_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(OS_WIN) && defined(_PREFAST_)
+
+// std::get() in <=libstdc++-4.6 returns an lvalue-reference for
+// rvalue-reference of a tuple, where an rvalue-reference is expected.
+template <size_t I, typename... Ts>
+typename std::tuple_element<I, std::tuple<Ts...>>::type&& get(
+    std::tuple<Ts...>&& t) {
+  using ElemType = typename std::tuple_element<I, std::tuple<Ts...>>::type;
+  return std::forward<ElemType>(std::get<I>(t));
+}
+
+template <size_t I, typename T>
+auto get(T& t) -> decltype(std::get<I>(t)) {
+  return std::get<I>(t);
+}
+
+template <size_t N>
+using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type;
+
+// 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... Ts, size_t... Ns>
+inline void DispatchToMethodImpl(const ObjT& obj,
+                                 Method method,
+                                 const std::tuple<Ts...>& arg,
+                                 IndexSequence<Ns...>) {
+  (obj->*method)(internal::Unwrap(std::get<Ns>(arg))...);
+}
+
+template <typename ObjT, typename Method, typename... Ts>
+inline void DispatchToMethod(const ObjT& obj,
+                             Method method,
+                             const std::tuple<Ts...>& arg) {
+  DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>());
+}
+
+// Static Dispatchers with no out params.
+
+template <typename Function, typename... Ts, size_t... Ns>
+inline void DispatchToFunctionImpl(Function function,
+                                   const std::tuple<Ts...>& arg,
+                                   IndexSequence<Ns...>) {
+  (*function)(internal::Unwrap(std::get<Ns>(arg))...);
+}
+
+template <typename Function, typename... Ts>
+inline void DispatchToFunction(Function function,
+                               const std::tuple<Ts...>& arg) {
+  DispatchToFunctionImpl(function, arg, MakeIndexSequence<sizeof...(Ts)>());
+}
+
+// Dispatchers with out parameters.
+
+template <typename ObjT,
+          typename Method,
+          typename... InTs,
+          typename... OutTs,
+          size_t... InNs,
+          size_t... OutNs>
+inline void DispatchToMethodImpl(const ObjT& obj,
+                                 Method method,
+                                 const std::tuple<InTs...>& in,
+                                 std::tuple<OutTs...>* out,
+                                 IndexSequence<InNs...>,
+                                 IndexSequence<OutNs...>) {
+  (obj->*method)(internal::Unwrap(std::get<InNs>(in))...,
+                 &std::get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename... InTs, typename... OutTs>
+inline void DispatchToMethod(const ObjT& obj,
+                             Method method,
+                             const std::tuple<InTs...>& in,
+                             std::tuple<OutTs...>* out) {
+  DispatchToMethodImpl(obj, method, in, out,
+                       MakeIndexSequence<sizeof...(InTs)>(),
+                       MakeIndexSequence<sizeof...(OutTs)>());
+}
+
+}  // namespace base
+
+#endif  // BASE_TUPLE_H_
diff --git a/libchrome/base/tuple_unittest.cc b/libchrome/base/tuple_unittest.cc
new file mode 100644
index 0000000..6f90c29
--- /dev/null
+++ b/libchrome/base/tuple_unittest.cc
@@ -0,0 +1,143 @@
+// 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) {
+  std::tuple<> t0 = std::make_tuple();
+  ALLOW_UNUSED_LOCAL(t0);
+  std::tuple<int> t1(1);
+  std::tuple<int, const char*> t2 =
+      std::make_tuple(1, static_cast<const char*>("wee"));
+  ALLOW_UNUSED_LOCAL(t2);
+  std::tuple<int, int, int> t3(1, 2, 3);
+  std::tuple<int, int, int, int*> t4(1, 2, 3, &std::get<0>(t1));
+  std::tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &std::get<0>(t4));
+  std::tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &std::get<0>(t4));
+
+  EXPECT_EQ(1, std::get<0>(t1));
+  DispatchToFunction(&DoAdd, t4);
+  EXPECT_EQ(6, std::get<0>(t1));
+
+  int res = 0;
+  DispatchToFunction(&DoAdd, std::make_tuple(9, 8, 7, &res));
+  EXPECT_EQ(24, res);
+
+  Addy addy;
+  EXPECT_EQ(1, std::get<0>(t4));
+  DispatchToMethod(&addy, &Addy::DoAdd, t5);
+  EXPECT_EQ(10, std::get<0>(t4));
+
+  Addz addz;
+  EXPECT_EQ(10, std::get<0>(t4));
+  DispatchToMethod(&addz, &Addz::DoAdd, t6);
+  EXPECT_EQ(15, std::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.
+  std::tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
+  std::get<1>(tuple) = &std::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);
+}
+
+TEST(TupleTest, Get) {
+  int i = 1;
+  int j = 2;
+  std::tuple<int, int&, int&&> t(3, i, std::move(j));
+  EXPECT_TRUE((std::is_same<int&, decltype(base::get<0>(t))>::value));
+  EXPECT_EQ(3, base::get<0>(t));
+
+  EXPECT_TRUE((std::is_same<int&, decltype(base::get<1>(t))>::value));
+  EXPECT_EQ(1, base::get<1>(t));
+
+  EXPECT_TRUE((std::is_same<int&, decltype(base::get<2>(t))>::value));
+  EXPECT_EQ(2, base::get<2>(t));
+
+  EXPECT_TRUE((std::is_same<int&&,
+               decltype(base::get<0>(std::move(t)))>::value));
+  EXPECT_EQ(3, base::get<0>(std::move(t)));
+
+  EXPECT_TRUE((std::is_same<int&,
+               decltype(base::get<1>(std::move(t)))>::value));
+  EXPECT_EQ(1, base::get<1>(std::move(t)));
+
+  EXPECT_TRUE((std::is_same<int&&,
+               decltype(base::get<2>(std::move(t)))>::value));
+  EXPECT_EQ(2, base::get<2>(std::move(t)));
+}
+
+}  // namespace base
diff --git a/libchrome/base/values.cc b/libchrome/base/values.cc
new file mode 100644
index 0000000..d579699
--- /dev/null
+++ b/libchrome/base/values.cc
@@ -0,0 +1,1169 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <utility>
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+std::unique_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.
+std::unique_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) {
+  std::unique_ptr<ListValue> copy;
+  for (const auto& entry : list) {
+    std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(*entry);
+    if (child_copy) {
+      if (!copy)
+        copy.reset(new ListValue);
+      copy->Append(std::move(child_copy));
+    }
+  }
+  return copy;
+}
+
+std::unique_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren(
+    const DictionaryValue& dict) {
+  std::unique_ptr<DictionaryValue> copy;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(it.value());
+    if (child_copy) {
+      if (!copy)
+        copy.reset(new DictionaryValue);
+      copy->SetWithoutPathExpansion(it.key(), std::move(child_copy));
+    }
+  }
+  return copy;
+}
+
+std::unique_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();
+  }
+}
+
+}  // namespace
+
+Value::~Value() {
+}
+
+// static
+std::unique_ptr<Value> Value::CreateNullValue() {
+  return WrapUnique(new Value(TYPE_NULL));
+}
+
+bool Value::GetAsBinary(const BinaryValue**) const {
+  return false;
+}
+
+bool Value::GetAsBoolean(bool*) const {
+  return false;
+}
+
+bool Value::GetAsInteger(int*) const {
+  return false;
+}
+
+bool Value::GetAsDouble(double*) const {
+  return false;
+}
+
+bool Value::GetAsString(std::string*) const {
+  return false;
+}
+
+bool Value::GetAsString(string16*) const {
+  return false;
+}
+
+bool Value::GetAsString(const StringValue**) const {
+  return false;
+}
+
+bool Value::GetAsList(ListValue**) {
+  return false;
+}
+
+bool Value::GetAsList(const ListValue**) const {
+  return false;
+}
+
+bool Value::GetAsDictionary(DictionaryValue**) {
+  return false;
+}
+
+bool Value::GetAsDictionary(const DictionaryValue**) 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();
+}
+
+std::unique_ptr<Value> Value::CreateDeepCopy() const {
+  return WrapUnique(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(std::unique_ptr<char[]> buffer, size_t size)
+    : Value(TYPE_BINARY), buffer_(std::move(buffer)), size_(size) {}
+
+BinaryValue::~BinaryValue() {
+}
+
+// static
+std::unique_ptr<BinaryValue> BinaryValue::CreateWithCopiedBuffer(
+    const char* buffer,
+    size_t size) {
+  std::unique_ptr<char[]> buffer_copy(new char[size]);
+  memcpy(buffer_copy.get(), buffer, size);
+  return base::MakeUnique<BinaryValue>(std::move(buffer_copy), 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_).release();
+}
+
+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 ////////////////////
+
+// static
+std::unique_ptr<DictionaryValue> DictionaryValue::From(
+    std::unique_ptr<Value> value) {
+  DictionaryValue* out;
+  if (value && value->GetAsDictionary(&out)) {
+    ignore_result(value.release());
+    return WrapUnique(out);
+  }
+  return nullptr;
+}
+
+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));
+  auto current_entry = dictionary_.find(key);
+  DCHECK((current_entry == dictionary_.end()) || current_entry->second);
+  return current_entry != dictionary_.end();
+}
+
+void DictionaryValue::Clear() {
+  dictionary_.clear();
+}
+
+void DictionaryValue::Set(const std::string& path,
+                          std::unique_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,
+                                              std::move(in_value));
+}
+
+void DictionaryValue::Set(const std::string& path, Value* in_value) {
+  Set(path, WrapUnique(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,
+                                              std::unique_ptr<Value> in_value) {
+  dictionary_[key] = std::move(in_value);
+}
+
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+                                              Value* in_value) {
+  SetWithoutPathExpansion(key, WrapUnique(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(StringPiece path,
+                          const Value** out_value) const {
+  DCHECK(IsStringUTF8(path));
+  StringPiece 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->GetDictionaryWithoutPathExpansion(
+            current_path.substr(0, delimiter_position).as_string(),
+            &child_dictionary)) {
+      return false;
+    }
+
+    current_dictionary = child_dictionary;
+    current_path = current_path.substr(delimiter_position + 1);
+  }
+
+  return current_dictionary->GetWithoutPathExpansion(current_path.as_string(),
+                                                     out_value);
+}
+
+bool DictionaryValue::Get(StringPiece 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(StringPiece 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(StringPiece 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));
+  auto entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  if (out_value)
+    *out_value = entry_iterator->second.get();
+  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,
+                             std::unique_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,
+    std::unique_ptr<Value>* out_value) {
+  DCHECK(IsStringUTF8(key));
+  auto entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  if (out_value)
+    *out_value = std::move(entry_iterator->second);
+  dictionary_.erase(entry_iterator);
+  return true;
+}
+
+bool DictionaryValue::RemovePath(const std::string& path,
+                                 std::unique_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;
+}
+
+std::unique_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren()
+    const {
+  std::unique_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(const Iterator& other) = default;
+
+DictionaryValue::Iterator::~Iterator() {}
+
+DictionaryValue* DictionaryValue::DeepCopy() const {
+  DictionaryValue* result = new DictionaryValue;
+
+  for (const auto& current_entry : dictionary_) {
+    result->SetWithoutPathExpansion(current_entry.first,
+                                    current_entry.second->CreateDeepCopy());
+  }
+
+  return result;
+}
+
+std::unique_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const {
+  return WrapUnique(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 ////////////////////
+
+// static
+std::unique_ptr<ListValue> ListValue::From(std::unique_ptr<Value> value) {
+  ListValue* out;
+  if (value && value->GetAsList(&out)) {
+    ignore_result(value.release());
+    return WrapUnique(out);
+  }
+  return nullptr;
+}
+
+ListValue::ListValue() : Value(TYPE_LIST) {
+}
+
+ListValue::~ListValue() {
+  Clear();
+}
+
+void ListValue::Clear() {
+  list_.clear();
+}
+
+bool ListValue::Set(size_t index, Value* in_value) {
+  return Set(index, WrapUnique(in_value));
+}
+
+bool ListValue::Set(size_t index, std::unique_ptr<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(std::move(in_value));
+  } else {
+    // TODO(dcheng): remove this DCHECK once the raw pointer version is removed?
+    DCHECK(list_[index] != in_value);
+    list_[index] = std::move(in_value);
+  }
+  return true;
+}
+
+bool ListValue::Get(size_t index, const Value** out_value) const {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    *out_value = list_[index].get();
+
+  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, std::unique_ptr<Value>* out_value) {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    *out_value = std::move(list_[index]);
+
+  list_.erase(list_.begin() + index);
+  return true;
+}
+
+bool ListValue::Remove(const Value& value, size_t* index) {
+  for (auto it = list_.begin(); it != list_.end(); ++it) {
+    if ((*it)->Equals(&value)) {
+      size_t previous_index = it - list_.begin();
+      list_.erase(it);
+
+      if (index)
+        *index = previous_index;
+      return true;
+    }
+  }
+  return false;
+}
+
+ListValue::iterator ListValue::Erase(iterator iter,
+                                     std::unique_ptr<Value>* out_value) {
+  if (out_value)
+    *out_value = std::move(*Storage::iterator(iter));
+
+  return list_.erase(iter);
+}
+
+void ListValue::Append(std::unique_ptr<Value> in_value) {
+  list_.push_back(std::move(in_value));
+}
+
+void ListValue::Append(Value* in_value) {
+  DCHECK(in_value);
+  Append(WrapUnique(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 (const auto& entry : list_) {
+    if (entry->Equals(in_value)) {
+      delete in_value;
+      return false;
+    }
+  }
+  list_.emplace_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, WrapUnique(in_value));
+  return true;
+}
+
+ListValue::const_iterator ListValue::Find(const Value& value) const {
+  return std::find_if(list_.begin(), list_.end(),
+                      [&value](const std::unique_ptr<Value>& entry) {
+                        return entry->Equals(&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 (const auto& entry : list_)
+    result->Append(entry->CreateDeepCopy());
+
+  return result;
+}
+
+std::unique_ptr<ListValue> ListValue::CreateDeepCopy() const {
+  return WrapUnique(DeepCopy());
+}
+
+bool ListValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  const ListValue* other_list =
+      static_cast<const ListValue*>(other);
+  Storage::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->get()))
+      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/libchrome/base/values.h b/libchrome/base/values.h
new file mode 100644
index 0000000..e3d6089
--- /dev/null
+++ b/libchrome/base/values.h
@@ -0,0 +1,569 @@
+// Copyright (c) 2012 The Chromium 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_t 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 <stdint.h>
+
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+class BinaryValue;
+class DictionaryValue;
+class FundamentalValue;
+class ListValue;
+class StringValue;
+class Value;
+
+// 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 std::unique_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.
+  std::unique_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(std::unique_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 std::unique_ptr<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:
+  std::unique_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:
+  using Storage = std::map<std::string, std::unique_ptr<Value>>;
+  // Returns |value| if it is a dictionary, nullptr otherwise.
+  static std::unique_ptr<DictionaryValue> From(std::unique_ptr<Value> value);
+
+  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, std::unique_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,
+                               std::unique_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(StringPiece path, const Value** out_value) const;
+  bool Get(StringPiece 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(StringPiece path,
+                     const DictionaryValue** out_value) const;
+  bool GetDictionary(StringPiece 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,
+                      std::unique_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,
+                                          std::unique_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,
+                          std::unique_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.
+  std::unique_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(const Iterator& other);
+    ~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_;
+    Storage::const_iterator it_;
+  };
+
+  // Overridden from Value:
+  DictionaryValue* DeepCopy() const override;
+  // Preferred version of DeepCopy. TODO(estade): remove the above.
+  std::unique_ptr<DictionaryValue> CreateDeepCopy() const;
+  bool Equals(const Value* other) const override;
+
+ private:
+  Storage dictionary_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryValue);
+};
+
+// This type of Value represents a list of other Value values.
+class BASE_EXPORT ListValue : public Value {
+ public:
+  using Storage = std::vector<std::unique_ptr<Value>>;
+  using const_iterator = Storage::const_iterator;
+  using iterator = Storage::iterator;
+
+  // Returns |value| if it is a list, nullptr otherwise.
+  static std::unique_ptr<ListValue> From(std::unique_ptr<Value> value);
+
+  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, std::unique_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, std::unique_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, std::unique_ptr<Value>* out_value);
+
+  // Appends a Value to the end of the list.
+  void Append(std::unique_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.
+  std::unique_ptr<ListValue> CreateDeepCopy() const;
+
+ private:
+  Storage 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 std::unique_ptr<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/libchrome/base/values_unittest.cc b/libchrome/base/values_unittest.cc
new file mode 100644
index 0000000..d685222
--- /dev/null
+++ b/libchrome/base/values_unittest.cc
@@ -0,0 +1,1156 @@
+// Copyright (c) 2012 The Chromium Authors. All 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 <stddef.h>
+
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.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));
+
+  std::unique_ptr<ListValue> new_toolbar_bookmarks(new ListValue);
+  settings.Set("global.toolbar.bookmarks", std::move(new_toolbar_bookmarks));
+  ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
+
+  std::unique_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
+  new_bookmark->SetString("name", "Froogle");
+  new_bookmark->SetString("url", "http://froogle.com");
+  toolbar_bookmarks->Append(std::move(new_bookmark));
+
+  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) {
+  std::unique_ptr<ListValue> mixed_list(new ListValue());
+  mixed_list->Set(0, WrapUnique(new FundamentalValue(true)));
+  mixed_list->Set(1, WrapUnique(new FundamentalValue(42)));
+  mixed_list->Set(2, WrapUnique(new FundamentalValue(88.8)));
+  mixed_list->Set(3, WrapUnique(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.
+  std::unique_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
+  std::unique_ptr<char[]> buffer(new char[15]);
+  char* original_buffer = buffer.get();
+  binary.reset(new BinaryValue(std::move(buffer), 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 = 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.
+  std::unique_ptr<Value> narrow_value(new StringValue("narrow"));
+  ASSERT_TRUE(narrow_value.get());
+  ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING));
+  std::unique_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(WrapUnique(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    ListValue list;
+    list.Append(WrapUnique(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    list.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    ListValue list;
+    list.Append(WrapUnique(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;
+  std::unique_ptr<Value> removed_item;
+
+  {
+    ListValue list;
+    list.Append(WrapUnique(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(WrapUnique(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;
+    std::unique_ptr<DeletionTestValue> value(
+        new DeletionTestValue(&deletion_flag));
+    DeletionTestValue* original_value = value.get();
+    list.Append(std::move(value));
+    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, WrapUnique(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, WrapUnique(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    dict.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, WrapUnique(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;
+  std::unique_ptr<Value> removed_item;
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, WrapUnique(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, WrapUnique(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);
+
+  std::unique_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;
+  std::unique_ptr<Value> scoped_null = Value::CreateNullValue();
+  Value* original_null = scoped_null.get();
+  original_dict.Set("null", std::move(scoped_null));
+  std::unique_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
+  FundamentalValue* original_bool = scoped_bool.get();
+  original_dict.Set("bool", std::move(scoped_bool));
+  std::unique_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
+  FundamentalValue* original_int = scoped_int.get();
+  original_dict.Set("int", std::move(scoped_int));
+  std::unique_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
+  FundamentalValue* original_double = scoped_double.get();
+  original_dict.Set("double", std::move(scoped_double));
+  std::unique_ptr<StringValue> scoped_string(new StringValue("hello"));
+  StringValue* original_string = scoped_string.get();
+  original_dict.Set("string", std::move(scoped_string));
+  std::unique_ptr<StringValue> scoped_string16(
+      new StringValue(ASCIIToUTF16("hello16")));
+  StringValue* original_string16 = scoped_string16.get();
+  original_dict.Set("string16", std::move(scoped_string16));
+
+  std::unique_ptr<char[]> original_buffer(new char[42]);
+  memset(original_buffer.get(), '!', 42);
+  std::unique_ptr<BinaryValue> scoped_binary(
+      new BinaryValue(std::move(original_buffer), 42));
+  BinaryValue* original_binary = scoped_binary.get();
+  original_dict.Set("binary", std::move(scoped_binary));
+
+  std::unique_ptr<ListValue> scoped_list(new ListValue());
+  Value* original_list = scoped_list.get();
+  std::unique_ptr<FundamentalValue> scoped_list_element_0(
+      new FundamentalValue(0));
+  Value* original_list_element_0 = scoped_list_element_0.get();
+  scoped_list->Append(std::move(scoped_list_element_0));
+  std::unique_ptr<FundamentalValue> scoped_list_element_1(
+      new FundamentalValue(1));
+  Value* original_list_element_1 = scoped_list_element_1.get();
+  scoped_list->Append(std::move(scoped_list_element_1));
+  original_dict.Set("list", std::move(scoped_list));
+
+  std::unique_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", std::move(scoped_nested_dictionary));
+
+  std::unique_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) {
+  std::unique_ptr<Value> null1(Value::CreateNullValue());
+  std::unique_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());
+
+  std::unique_ptr<DictionaryValue> copy = dv.CreateDeepCopy();
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  std::unique_ptr<ListValue> list(new ListValue);
+  ListValue* original_list = list.get();
+  list->Append(Value::CreateNullValue());
+  list->Append(WrapUnique(new DictionaryValue));
+  std::unique_ptr<Value> list_copy(list->CreateDeepCopy());
+
+  dv.Set("f", std::move(list));
+  EXPECT_FALSE(dv.Equals(copy.get()));
+  copy->Set("f", std::move(list_copy));
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  original_list->Append(WrapUnique(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) {
+  std::unique_ptr<Value> null1(Value::CreateNullValue());
+  std::unique_ptr<Value> null2(Value::CreateNullValue());
+  EXPECT_TRUE(Value::Equals(null1.get(), null2.get()));
+  EXPECT_TRUE(Value::Equals(NULL, NULL));
+
+  std::unique_ptr<Value> i42(new FundamentalValue(42));
+  std::unique_ptr<Value> j42(new FundamentalValue(42));
+  std::unique_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;
+  std::unique_ptr<Value> scoped_null(Value::CreateNullValue());
+  Value* original_null = scoped_null.get();
+  original_dict.Set("null", std::move(scoped_null));
+  std::unique_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
+  Value* original_bool = scoped_bool.get();
+  original_dict.Set("bool", std::move(scoped_bool));
+  std::unique_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
+  Value* original_int = scoped_int.get();
+  original_dict.Set("int", std::move(scoped_int));
+  std::unique_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
+  Value* original_double = scoped_double.get();
+  original_dict.Set("double", std::move(scoped_double));
+  std::unique_ptr<StringValue> scoped_string(new StringValue("hello"));
+  Value* original_string = scoped_string.get();
+  original_dict.Set("string", std::move(scoped_string));
+  std::unique_ptr<StringValue> scoped_string16(
+      new StringValue(ASCIIToUTF16("hello16")));
+  Value* original_string16 = scoped_string16.get();
+  original_dict.Set("string16", std::move(scoped_string16));
+
+  std::unique_ptr<char[]> original_buffer(new char[42]);
+  memset(original_buffer.get(), '!', 42);
+  std::unique_ptr<BinaryValue> scoped_binary(
+      new BinaryValue(std::move(original_buffer), 42));
+  Value* original_binary = scoped_binary.get();
+  original_dict.Set("binary", std::move(scoped_binary));
+
+  std::unique_ptr<ListValue> scoped_list(new ListValue());
+  Value* original_list = scoped_list.get();
+  std::unique_ptr<FundamentalValue> scoped_list_element_0(
+      new FundamentalValue(0));
+  scoped_list->Append(std::move(scoped_list_element_0));
+  std::unique_ptr<FundamentalValue> scoped_list_element_1(
+      new FundamentalValue(1));
+  scoped_list->Append(std::move(scoped_list_element_1));
+  original_dict.Set("list", std::move(scoped_list));
+
+  std::unique_ptr<Value> copy_dict = original_dict.CreateDeepCopy();
+  std::unique_ptr<Value> copy_null = original_null->CreateDeepCopy();
+  std::unique_ptr<Value> copy_bool = original_bool->CreateDeepCopy();
+  std::unique_ptr<Value> copy_int = original_int->CreateDeepCopy();
+  std::unique_ptr<Value> copy_double = original_double->CreateDeepCopy();
+  std::unique_ptr<Value> copy_string = original_string->CreateDeepCopy();
+  std::unique_ptr<Value> copy_string16 = original_string16->CreateDeepCopy();
+  std::unique_ptr<Value> copy_binary = original_binary->CreateDeepCopy();
+  std::unique_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) {
+  std::unique_ptr<DictionaryValue> root(new DictionaryValue);
+  // Remove empty lists and dictionaries.
+  root->Set("empty_dict", WrapUnique(new DictionaryValue));
+  root->Set("empty_list", WrapUnique(new ListValue));
+  root->SetWithoutPathExpansion("a.b.c.d.e",
+                                WrapUnique(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", WrapUnique(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", WrapUnique(new DictionaryValue));
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    std::unique_ptr<DictionaryValue> inner(new DictionaryValue);
+    inner->Set("empty_dict", WrapUnique(new DictionaryValue));
+    inner->Set("empty_list", WrapUnique(new ListValue));
+    root->Set("dict_with_empty_children", std::move(inner));
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    std::unique_ptr<ListValue> inner(new ListValue);
+    inner->Append(WrapUnique(new DictionaryValue));
+    inner->Append(WrapUnique(new ListValue));
+    root->Set("list_with_empty_children", std::move(inner));
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Nested with siblings.
+  {
+    std::unique_ptr<ListValue> inner(new ListValue());
+    inner->Append(WrapUnique(new DictionaryValue));
+    inner->Append(WrapUnique(new ListValue));
+    root->Set("list_with_empty_children", std::move(inner));
+    std::unique_ptr<DictionaryValue> inner2(new DictionaryValue);
+    inner2->Set("empty_dict", WrapUnique(new DictionaryValue));
+    inner2->Set("empty_list", WrapUnique(new ListValue));
+    root->Set("dict_with_empty_children", std::move(inner2));
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Make sure nested values don't get pruned.
+  {
+    std::unique_ptr<ListValue> inner(new ListValue);
+    std::unique_ptr<ListValue> inner2(new ListValue);
+    inner2->Append(WrapUnique(new StringValue("hello")));
+    inner->Append(WrapUnique(new DictionaryValue));
+    inner->Append(std::move(inner2));
+    root->Set("list_with_empty_children", std::move(inner));
+    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) {
+  std::unique_ptr<DictionaryValue> base(new DictionaryValue);
+  base->SetString("base_key", "base_key_value_base");
+  base->SetString("collide_key", "collide_key_value_base");
+  std::unique_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", std::move(base_sub_dict));
+
+  std::unique_ptr<DictionaryValue> merge(new DictionaryValue);
+  merge->SetString("merge_key", "merge_key_value_merge");
+  merge->SetString("collide_key", "collide_key_value_merge");
+  std::unique_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", std::move(merge_sub_dict));
+
+  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) {
+  std::unique_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);
+
+  std::unique_ptr<DictionaryValue> base(new DictionaryValue);
+  base->Set("dict", std::move(child));
+  EXPECT_EQ(1U, base->size());
+
+  DictionaryValue* ptr;
+  EXPECT_TRUE(base->GetDictionary("dict", &ptr));
+  EXPECT_EQ(original_child, ptr);
+
+  std::unique_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/libchrome/base/version.cc b/libchrome/base/version.cc
new file mode 100644
index 0000000..02213fb
--- /dev/null
+++ b/libchrome/base/version.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/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<StringPiece> numbers =
+      SplitStringPiece(version_str, ".", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  if (numbers.empty())
+    return false;
+
+  for (auto it = numbers.begin(); it != numbers.end(); ++it) {
+    if (StartsWith(*it, "+", CompareCase::SENSITIVE))
+      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(const Version& other) = default;
+
+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(version_string, ".*", CompareCase::SENSITIVE))
+    version_string.resize(version_string.size() - 2);
+
+  Version version(version_string);
+  return version.IsValid();
+}
+
+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, ".*", CompareCase::SENSITIVE)) {
+    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;
+}
+
+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(UintToString(components_[i]));
+    version_str.append(".");
+  }
+  version_str.append(UintToString(components_[count - 1]));
+  return version_str;
+}
+
+bool operator==(const Version& v1, const Version& v2) {
+  return v1.CompareTo(v2) == 0;
+}
+
+bool operator!=(const Version& v1, const Version& v2) {
+  return !(v1 == v2);
+}
+
+bool operator<(const Version& v1, const Version& v2) {
+  return v1.CompareTo(v2) < 0;
+}
+
+bool operator<=(const Version& v1, const Version& v2) {
+  return v1.CompareTo(v2) <= 0;
+}
+
+bool operator>(const Version& v1, const Version& v2) {
+  return v1.CompareTo(v2) > 0;
+}
+
+bool operator>=(const Version& v1, const Version& v2) {
+  return v1.CompareTo(v2) >= 0;
+}
+
+std::ostream& operator<<(std::ostream& stream, const Version& v) {
+  return stream << v.GetString();
+}
+
+}  // namespace base
diff --git a/libchrome/base/version.h b/libchrome/base/version.h
new file mode 100644
index 0000000..25b570a
--- /dev/null
+++ b/libchrome/base/version.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_VERSION_H_
+#define BASE_VERSION_H_
+
+#include <stdint.h>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "base/base_export.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(const Version& other);
+
+  ~Version();
+
+  // Initializes from a decimal dotted version number, like "0.1.1".
+  // Each component is limited to a uint16_t. 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);
+
+  // 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_;
+};
+
+BASE_EXPORT bool operator==(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator!=(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator<(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator<=(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator>(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator>=(const Version& v1, const Version& v2);
+BASE_EXPORT std::ostream& operator<<(std::ostream& stream, const Version& v);
+
+}  // 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/libchrome/base/version_unittest.cc b/libchrome/base/version_unittest.cc
new file mode 100644
index 0000000..5d9ea99
--- /dev/null
+++ b/libchrome/base/version_unittest.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/version.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.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_EQ(v1, v2);
+  }
+  EXPECT_EQ(v3, 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;
+
+    // Test comparison operators
+    switch (cases[i].expected) {
+    case -1:
+      EXPECT_LT(lhs, rhs);
+      EXPECT_LE(lhs, rhs);
+      EXPECT_NE(lhs, rhs);
+      EXPECT_FALSE(lhs == rhs);
+      EXPECT_FALSE(lhs >= rhs);
+      EXPECT_FALSE(lhs > rhs);
+      break;
+    case 0:
+      EXPECT_FALSE(lhs < rhs);
+      EXPECT_LE(lhs, rhs);
+      EXPECT_FALSE(lhs != rhs);
+      EXPECT_EQ(lhs, rhs);
+      EXPECT_GE(lhs, rhs);
+      EXPECT_FALSE(lhs > rhs);
+      break;
+    case 1:
+      EXPECT_FALSE(lhs < rhs);
+      EXPECT_FALSE(lhs <= rhs);
+      EXPECT_NE(lhs, rhs);
+      EXPECT_FALSE(lhs == rhs);
+      EXPECT_GE(lhs, rhs);
+      EXPECT_GT(lhs, rhs);
+      break;
+    }
+  }
+}
+
+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/libchrome/base/vlog.cc b/libchrome/base/vlog.cc
new file mode 100644
index 0000000..c00e631
--- /dev/null
+++ b/libchrome/base/vlog.cc
@@ -0,0 +1,181 @@
+// 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 <stddef.h>
+
+#include <ostream>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.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/libchrome/base/vlog.h b/libchrome/base/vlog.h
new file mode 100644
index 0000000..2950904
--- /dev/null
+++ b/libchrome/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/macros.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/libchrome/base/vlog_unittest.cc b/libchrome/base/vlog_unittest.cc
new file mode 100644
index 0000000..3c3f49c
--- /dev/null
+++ b/libchrome/base/vlog_unittest.cc
@@ -0,0 +1,124 @@
+// 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/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/libchrome/base/win/OWNERS b/libchrome/base/win/OWNERS
new file mode 100644
index 0000000..78473b9
--- /dev/null
+++ b/libchrome/base/win/OWNERS
@@ -0,0 +1,4 @@
+cpu@chromium.org
+grt@chromium.org
+jschuh@chromium.org
+scottmg@chromium.org
diff --git a/libchrome/base/win/event_trace_consumer.h b/libchrome/base/win/event_trace_consumer.h
new file mode 100644
index 0000000..9f97e0d
--- /dev/null
+++ b/libchrome/base/win/event_trace_consumer.h
@@ -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.
+//
+// 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 <stddef.h>
+#include <vector>
+
+#include "base/macros.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/libchrome/base/win/scoped_co_mem.h b/libchrome/base/win/scoped_co_mem.h
new file mode 100644
index 0000000..a3737dd
--- /dev/null
+++ b/libchrome/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/logging.h"
+#include "base/macros.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/libchrome/base/win/scoped_com_initializer.h b/libchrome/base/win/scoped_com_initializer.h
new file mode 100644
index 0000000..8efff85
--- /dev/null
+++ b/libchrome/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/logging.h"
+#include "base/macros.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/libchrome/base/win/scoped_comptr.h b/libchrome/base/win/scoped_comptr.h
new file mode 100644
index 0000000..5ce60e2
--- /dev/null
+++ b/libchrome/base/win/scoped_comptr.h
@@ -0,0 +1,168 @@
+// 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.
+    static_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 (this->ptr_ != NULL) {
+      this->ptr_->Release();
+      this->ptr_ = NULL;
+    }
+  }
+
+  // Sets the internal pointer to NULL and returns the held object without
+  // releasing the reference.
+  Interface* Detach() {
+    Interface* p = this->ptr_;
+    this->ptr_ = NULL;
+    return p;
+  }
+
+  // Accepts an interface pointer that has already been addref-ed.
+  void Attach(Interface* p) {
+    DCHECK(!this->ptr_);
+    this->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(!this->ptr_) << "Object leak. Pointer must be NULL";
+    return &this->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(this->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 this->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(this->ptr_ != NULL);
+    return this->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(!this->ptr_);
+    HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
+                                    reinterpret_cast<void**>(&this->ptr_));
+    return hr;
+  }
+
+  // Checks if the identity of |other| and this object is the same.
+  bool IsSameObject(IUnknown* other) {
+    if (!other && !this->ptr_)
+      return true;
+
+    if (!other || !this->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(this->ptr_ != NULL);
+    return reinterpret_cast<BlockIUnknownMethods*>(this->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/libchrome/base/win/scoped_gdi_object.h b/libchrome/base/win/scoped_gdi_object.h
new file mode 100644
index 0000000..9d8465b
--- /dev/null
+++ b/libchrome/base/win/scoped_gdi_object.h
@@ -0,0 +1,45 @@
+// 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/scoped_generic.h"
+
+namespace base {
+namespace win {
+
+namespace internal {
+
+template <class T>
+struct ScopedGDIObjectTraits {
+  static T InvalidValue() { return nullptr; }
+  static void Free(T object) { DeleteObject(object); }
+};
+
+// An explicit specialization for HICON because we have to call DestroyIcon()
+// instead of DeleteObject() for HICON.
+template <>
+void inline ScopedGDIObjectTraits<HICON>::Free(HICON icon) {
+  DestroyIcon(icon);
+}
+
+}  // namespace internal
+
+// Like ScopedHandle but for GDI objects.
+template <class T>
+using ScopedGDIObject = ScopedGeneric<T, internal::ScopedGDIObjectTraits<T>>;
+
+// 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/libchrome/base/win/scoped_handle_test_dll.cc b/libchrome/base/win/scoped_handle_test_dll.cc
new file mode 100644
index 0000000..c72e459
--- /dev/null
+++ b/libchrome/base/win/scoped_handle_test_dll.cc
@@ -0,0 +1,125 @@
+// Copyright 2016 The Chromium Authors. 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 <vector>
+
+#include "base/win/base_features.h"
+#include "base/win/current_module.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+namespace testing {
+
+extern "C" bool __declspec(dllexport) RunTest();
+
+namespace {
+
+struct ThreadParams {
+  HANDLE ready_event;
+  HANDLE start_event;
+};
+
+// Note, this must use all native functions to avoid instantiating the
+// ActiveVerifier. e.g. can't use base::Thread or even base::PlatformThread.
+DWORD __stdcall ThreadFunc(void* params) {
+  ThreadParams* thread_params = reinterpret_cast<ThreadParams*>(params);
+  HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
+
+  ::SetEvent(thread_params->ready_event);
+  ::WaitForSingleObject(thread_params->start_event, INFINITE);
+  ScopedHandle handle_holder(handle);
+  return 0;
+}
+
+bool InternalRunThreadTest() {
+  std::vector<HANDLE> threads_;
+  // From manual testing, the bug fixed by crrev.com/678736a starts reliably
+  // causing handle verifier asserts to trigger at around 100 threads, so make
+  // it 200 to be sure to detect any future regressions.
+  const size_t kNumThreads = 200;
+
+  // bManualReset is set to true to allow signalling multiple threads.
+  HANDLE start_event = ::CreateEvent(nullptr, true, false, nullptr);
+  if (!start_event)
+    return false;
+
+  HANDLE ready_event = CreateEvent(nullptr, false, false, nullptr);
+  if (!ready_event)
+    return false;
+
+  ThreadParams thread_params = { ready_event, start_event };
+
+  for (size_t i = 0; i < kNumThreads; i++) {
+    HANDLE thread_handle =
+        ::CreateThread(nullptr, 0, ThreadFunc,
+                       reinterpret_cast<void*>(&thread_params), 0, nullptr);
+    if (!thread_handle)
+      break;
+    ::WaitForSingleObject(ready_event, INFINITE);
+    threads_.push_back(thread_handle);
+  }
+
+  ::CloseHandle(ready_event);
+
+  if (threads_.size() != kNumThreads) {
+    for (const auto& thread : threads_)
+      ::CloseHandle(thread);
+    ::CloseHandle(start_event);
+    return false;
+  }
+
+  ::SetEvent(start_event);
+  ::CloseHandle(start_event);
+  for (const auto& thread : threads_) {
+    ::WaitForSingleObject(thread, INFINITE);
+    ::CloseHandle(thread);
+  }
+
+  return true;
+}
+
+bool InternalRunLocationTest() {
+  // Create a new handle and then set LastError again.
+  HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
+  if (!handle)
+    return false;
+  ScopedHandle handle_holder(handle);
+
+  HMODULE verifier_module = GetHandleVerifierModuleForTesting();
+  if (!verifier_module)
+    return false;
+
+  // Get my module
+  HMODULE my_module = CURRENT_MODULE();
+  if (!my_module)
+    return false;
+
+  HMODULE main_module = ::GetModuleHandle(NULL);
+
+#if BUILDFLAG(SINGLE_MODULE_MODE_HANDLE_VERIFIER)
+  // In a component build ActiveVerifier will always be created inside base.dll
+  // as the code always lives there.
+  if (verifier_module == my_module || verifier_module == main_module)
+    return false;
+#else
+  // In a non-component build, ActiveVerifier should always be created in the
+  // version of base linked with the main executable.
+  if (verifier_module == my_module || verifier_module != main_module)
+    return false;
+#endif
+  return true;
+}
+
+}  // namespace
+
+bool RunTest() {
+  return InternalRunThreadTest() && InternalRunLocationTest();
+}
+
+}  // testing
+}  // win
+}  // base
diff --git a/libchrome/base/win/scoped_hdc.h b/libchrome/base/win/scoped_hdc.h
new file mode 100644
index 0000000..fa686dd
--- /dev/null
+++ b/libchrome/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/logging.h"
+#include "base/macros.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/libchrome/base/win/scoped_hglobal.h b/libchrome/base/win/scoped_hglobal.h
new file mode 100644
index 0000000..abe9a5a
--- /dev/null
+++ b/libchrome/base/win/scoped_hglobal.h
@@ -0,0 +1,53 @@
+// 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 <stddef.h>
+
+#include "base/macros.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/libchrome/base/win/scoped_propvariant.h b/libchrome/base/win/scoped_propvariant.h
new file mode 100644
index 0000000..aa9afec
--- /dev/null
+++ b/libchrome/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/logging.h"
+#include "base/macros.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/libchrome/base/win/scoped_select_object.h b/libchrome/base/win/scoped_select_object.h
new file mode 100644
index 0000000..59b21c1
--- /dev/null
+++ b/libchrome/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/logging.h"
+#include "base/macros.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/libchrome/base/win/windows_version_unittest.cc b/libchrome/base/win/windows_version_unittest.cc
new file mode 100644
index 0000000..f0d6d96
--- /dev/null
+++ b/libchrome/base/win/windows_version_unittest.cc
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All 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 "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+namespace {
+
+TEST(WindowsVersion, GetVersionExAndKernelVersionMatch) {
+  // If this fails, we're running in compatibility mode, or need to update the
+  // application manifest.
+  EXPECT_EQ(OSInfo::GetInstance()->version(),
+            OSInfo::GetInstance()->Kernel32Version());
+}
+
+}  // namespace
+}  // namespace win
+}  // namespace base
diff --git a/libchrome/build/build_config.h b/libchrome/build/build_config.h
new file mode 100644
index 0000000..80a93d3
--- /dev/null
+++ b/libchrome/build/build_config.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2012 The Chromium 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 adds defines about the platform we're currently building on.
+//  Operating System:
+//    OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) /
+//    OS_NACL (NACL_SFI or NACL_NONSFI) / OS_NACL_SFI / OS_NACL_NONSFI
+//  Compiler:
+//    COMPILER_MSVC / COMPILER_GCC
+//  Processor:
+//    ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64)
+//    ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
+
+#ifndef BUILD_BUILD_CONFIG_H_
+#define BUILD_BUILD_CONFIG_H_
+
+// A brief primer on #defines:
+//
+// - __ANDROID__ is automatically defined by the Android toolchain (see
+//   https://goo.gl/v61lXa). It's not defined when building host code.
+// - __ANDROID_HOST__ is defined via -D by Android.mk when building host code
+//   within an Android checkout.
+// - ANDROID is defined via -D when building code for either Android targets or
+//   hosts. Use __ANDROID__ and __ANDROID_HOST__ instead.
+// - OS_ANDROID is a Chrome-specific define used to build Chrome for Android
+//   within the NDK.
+
+// Android targets and hosts don't use tcmalloc.
+#if defined(__ANDROID__) || defined(__ANDROID_HOST__)
+#define NO_TCMALLOC
+#endif  // defined(__ANDROID__) || defined(__ANDROID_HOST__)
+
+// Use the Chrome OS version of the code for both Android targets and Chrome OS builds.
+#if !defined(__ANDROID_HOST__)
+#define OS_CHROMEOS 1
+#endif  // !defined(__ANDROID_HOST__)
+
+#if defined(__ANDROID__)  // Android targets
+
+#define __linux__ 1
+#if defined(__BIONIC__)
+#define __UCLIBC__ 1
+#endif  // defined(__BIONIC__)
+
+#elif !defined(__ANDROID_HOST__)  // Chrome OS
+
+// TODO: Remove these once the GLib MessageLoopForUI isn't being used:
+// https://crbug.com/361635
+#define USE_GLIB 1
+#define USE_OZONE 1
+
+#endif  // defined(__ANDROID__)
+
+// A set of macros to use for platform detection.
+#if defined(__native_client__)
+// __native_client__ must be first, so that other OS_ defines are not set.
+#define OS_NACL 1
+// OS_NACL comes in two sandboxing technology flavors, SFI or Non-SFI.
+// PNaCl toolchain defines __native_client_nonsfi__ macro in Non-SFI build
+// mode, while it does not in SFI build mode.
+#if defined(__native_client_nonsfi__)
+#define OS_NACL_NONSFI
+#else
+#define OS_NACL_SFI
+#endif
+// Don't set OS_ANDROID; it's only used when building Chrome for Android.
+#elif defined(__APPLE__)
+// only include TargetConditions after testing ANDROID as some android builds
+// on mac don't have this header available and it's not needed unless the target
+// is really mac/ios.
+#include <TargetConditionals.h>
+#define OS_MACOSX 1
+#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#define OS_IOS 1
+#endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#elif defined(__linux__)
+#define OS_LINUX 1
+// include a system header to pull in features.h for glibc/uclibc macros.
+#include <unistd.h>
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+// we really are using glibc, not uClibc pretending to be glibc
+#define LIBC_GLIBC 1
+#endif
+#elif defined(_WIN32)
+#define OS_WIN 1
+#define TOOLKIT_VIEWS 1
+#elif defined(__FreeBSD__)
+#define OS_FREEBSD 1
+#elif defined(__OpenBSD__)
+#define OS_OPENBSD 1
+#elif defined(__sun)
+#define OS_SOLARIS 1
+#elif defined(__QNXNTO__)
+#define OS_QNX 1
+#else
+#error Please add support for your platform in build/build_config.h
+#endif
+
+#if defined(USE_OPENSSL_CERTS) && defined(USE_NSS_CERTS)
+#error Cannot use both OpenSSL and NSS for certificates
+#endif
+
+// For access to standard BSD features, use OS_BSD instead of a
+// more specific macro.
+#if defined(OS_FREEBSD) || defined(OS_OPENBSD)
+#define OS_BSD 1
+#endif
+
+// For access to standard POSIXish features, use OS_POSIX instead of a
+// more specific macro.
+#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) ||     \
+    defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) ||  \
+    defined(OS_NACL) || defined(OS_QNX)
+#define OS_POSIX 1
+#endif
+
+// Use tcmalloc
+#if (defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)) && \
+    !defined(NO_TCMALLOC)
+#define USE_TCMALLOC 1
+#endif
+
+// Compiler detection.
+#if defined(__GNUC__)
+#define COMPILER_GCC 1
+#elif defined(_MSC_VER)
+#define COMPILER_MSVC 1
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+// Processor architecture detection.  For more info on what's defined, see:
+//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+//   http://www.agner.org/optimize/calling_conventions.pdf
+//   or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86_64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__ARMEL__)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARMEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__aarch64__)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARM64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__pnacl__)
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__MIPSEL__)
+#if defined(__LP64__)
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPS64EL 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#else
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPSEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#endif
+#else
+#error Please add support for your architecture in build/build_config.h
+#endif
+
+// Type detection for wchar_t.
+#if defined(OS_WIN)
+#define WCHAR_T_IS_UTF16
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \
+    defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
+#define WCHAR_T_IS_UTF32
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \
+    defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
+// On Posix, we'll detect short wchar_t, but projects aren't guaranteed to
+// compile in this mode (in particular, Chrome doesn't). This is intended for
+// other projects using base who manage their own dependencies and make sure
+// short wchar works for them.
+#define WCHAR_T_IS_UTF16
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+#if defined(OS_ANDROID)
+// The compiler thinks std::string::const_iterator and "const char*" are
+// equivalent types.
+#define STD_STRING_ITERATOR_IS_CHAR_POINTER
+// The compiler thinks base::string16::const_iterator and "char16*" are
+// equivalent types.
+#define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER
+#endif
+
+#endif  // BUILD_BUILD_CONFIG_H_
diff --git a/libchrome/build/buildflag.h b/libchrome/build/buildflag.h
new file mode 100644
index 0000000..5776a75
--- /dev/null
+++ b/libchrome/build/buildflag.h
@@ -0,0 +1,47 @@
+// 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 BUILD_BUILDFLAG_H_
+#define BUILD_BUILDFLAG_H_
+
+// These macros un-mangle the names of the build flags in a way that looks
+// natural, and gives errors if the flag is not defined. Normally in the
+// preprocessor it's easy to make mistakes that interpret "you haven't done
+// the setup to know what the flag is" as "flag is off". Normally you would
+// include the generated header rather than include this file directly.
+//
+// This is for use with generated headers. See build/buildflag_header.gni.
+
+// This dance of two macros does a concatenation of two preprocessor args using
+// ## doubly indirectly because using ## directly prevents macros in that
+// parameter from being expanded.
+#define BUILDFLAG_CAT_INDIRECT(a, b) a ## b
+#define BUILDFLAG_CAT(a, b) BUILDFLAG_CAT_INDIRECT(a, b)
+
+// Accessor for build flags.
+//
+// To test for a value, if the build file specifies:
+//
+//   ENABLE_FOO=true
+//
+// Then you would check at build-time in source code with:
+//
+//   #include "foo_flags.h"  // The header the build file specified.
+//
+//   #if BUILDFLAG(ENABLE_FOO)
+//     ...
+//   #endif
+//
+// There will no #define called ENABLE_FOO so if you accidentally test for
+// whether that is defined, it will always be negative. You can also use
+// the value in expressions:
+//
+//   const char kSpamServerName[] = BUILDFLAG(SPAM_SERVER_NAME);
+//
+// Because the flag is accessed as a preprocessor macro with (), an error
+// will be thrown if the proper header defining the internal flag value has
+// not been included.
+#define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)())
+
+#endif  // BUILD_BUILDFLAG_H_
diff --git a/libchrome/components/timers/BUILD.gn b/libchrome/components/timers/BUILD.gn
new file mode 100644
index 0000000..c6f4a12
--- /dev/null
+++ b/libchrome/components/timers/BUILD.gn
@@ -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.
+
+static_library("timers") {
+  sources = [
+    "alarm_timer_chromeos.cc",
+    "alarm_timer_chromeos.h",
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "alarm_timer_unittest.cc",
+  ]
+
+  deps = [
+    ":timers",
+    "//base",
+    "//testing/gtest",
+  ]
+}
diff --git a/libchrome/components/timers/DEPS b/libchrome/components/timers/DEPS
new file mode 100644
index 0000000..413f57b
--- /dev/null
+++ b/libchrome/components/timers/DEPS
@@ -0,0 +1,10 @@
+include_rules = [
+  # This directory is shared with Chrome OS, which only links against
+  # base/.  We don't want any other dependencies to creep in.
+  "-build",
+  "-content",
+  "-library_loaders",
+  "-net",
+  "-third_party",
+  "-url",
+]
\ No newline at end of file
diff --git a/libchrome/components/timers/OWNERS b/libchrome/components/timers/OWNERS
new file mode 100644
index 0000000..0c43483
--- /dev/null
+++ b/libchrome/components/timers/OWNERS
@@ -0,0 +1,2 @@
+chirantan@chromium.org
+derat@chromium.org
diff --git a/libchrome/components/timers/README b/libchrome/components/timers/README
new file mode 100644
index 0000000..0b2b4e3
--- /dev/null
+++ b/libchrome/components/timers/README
@@ -0,0 +1,3 @@
+This directory hosts a timer class that is shared with Chrome OS.  Code that
+lives in this directory is not allowed to depend on anything other than base/
+because Chrome OS only pulls in and depends on base/ as a library.
diff --git a/libchrome/components/timers/alarm_timer_chromeos.cc b/libchrome/components/timers/alarm_timer_chromeos.cc
new file mode 100644
index 0000000..3f1abbf
--- /dev/null
+++ b/libchrome/components/timers/alarm_timer_chromeos.cc
@@ -0,0 +1,486 @@
+// 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 "components/timers/alarm_timer_chromeos.h"
+
+#include <stdint.h>
+#include <sys/timerfd.h>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/pending_task.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_event.h"
+
+namespace timers {
+namespace {
+// This class represents the IO thread that the AlarmTimer::Delegate may use for
+// watching file descriptors if it gets called from a thread that does not have
+// a MessageLoopForIO.  It is a lazy global instance because it may not always
+// be necessary.
+class RtcAlarmIOThread : public base::Thread {
+ public:
+  RtcAlarmIOThread() : Thread("RTC Alarm IO Thread") {
+    CHECK(
+        StartWithOptions(base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+  }
+  ~RtcAlarmIOThread() override { Stop(); }
+};
+
+base::LazyInstance<RtcAlarmIOThread> g_io_thread = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Watches a MessageLoop and runs a callback if that MessageLoop will be
+// destroyed.
+class AlarmTimer::MessageLoopObserver
+    : public base::MessageLoop::DestructionObserver {
+ public:
+  // Constructs a MessageLoopObserver that will observe |message_loop| and will
+  // call |on_will_be_destroyed_callback| when |message_loop| is about to be
+  // destroyed.
+  MessageLoopObserver(base::MessageLoop* message_loop,
+                      base::Closure on_will_be_destroyed_callback)
+      : message_loop_(message_loop),
+        on_will_be_destroyed_callback_(on_will_be_destroyed_callback) {
+    DCHECK(message_loop_);
+    message_loop_->AddDestructionObserver(this);
+  }
+
+  ~MessageLoopObserver() override {
+    // If |message_loop_| was destroyed, then this class will have already
+    // unregistered itself.  Doing it again will trigger a warning.
+    if (message_loop_)
+      message_loop_->RemoveDestructionObserver(this);
+  }
+
+  // base::MessageLoop::DestructionObserver override.
+  void WillDestroyCurrentMessageLoop() override {
+    message_loop_->RemoveDestructionObserver(this);
+    message_loop_ = NULL;
+
+    on_will_be_destroyed_callback_.Run();
+  }
+
+ private:
+  // The MessageLoop that this class should watch.  Is a weak pointer.
+  base::MessageLoop* message_loop_;
+
+  // The callback to run when |message_loop_| will be destroyed.
+  base::Closure on_will_be_destroyed_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver);
+};
+
+// This class manages a Real Time Clock (RTC) alarm, a feature that is available
+// from linux version 3.11 onwards.  It creates a file descriptor for the RTC
+// alarm timer and then watches that file descriptor to see when it can be read
+// without blocking, indicating that the timer has fired.
+//
+// A major problem for this class is that watching file descriptors is only
+// available on a MessageLoopForIO but there is no guarantee the timer is going
+// to be created on one.  To get around this, the timer has a dedicated thread
+// with a MessageLoopForIO that posts tasks back to the thread that started the
+// timer.
+class AlarmTimer::Delegate
+    : public base::RefCountedThreadSafe<AlarmTimer::Delegate>,
+      public base::MessageLoopForIO::Watcher {
+ public:
+  // Construct a Delegate for the AlarmTimer.  It should be safe to call
+  // |on_timer_fired_callback| multiple times.
+  explicit Delegate(base::Closure on_timer_fired_callback);
+
+  // Returns true if the system timer managed by this delegate is capable of
+  // waking the system from suspend.
+  bool CanWakeFromSuspend();
+
+  // Resets the timer to fire after |delay| has passed.  Cancels any
+  // pre-existing delay.
+  void Reset(base::TimeDelta delay);
+
+  // Stops the currently running timer.  It should be safe to call this even if
+  // the timer is not running.
+  void Stop();
+
+  // Sets a hook that will be called when the timer fires and a task has been
+  // queued on |origin_task_runner_|.  Used by tests to wait until a task is
+  // pending in the MessageLoop.
+  void SetTimerFiredCallbackForTest(base::Closure test_callback);
+
+  // base::MessageLoopForIO::Watcher overrides.
+  void OnFileCanReadWithoutBlocking(int fd) override;
+  void OnFileCanWriteWithoutBlocking(int fd) override;
+
+ private:
+  friend class base::RefCountedThreadSafe<Delegate>;
+  ~Delegate() override;
+
+  // Actually performs the system calls to set up the timer.  This must be
+  // called on a MessageLoopForIO.
+  void ResetImpl(base::TimeDelta delay, int reset_sequence_number);
+
+  // Callback that is run when the timer fires.  Must be run on
+  // |origin_task_runner_|.
+  void OnTimerFired(int reset_sequence_number);
+
+  // File descriptor associated with the alarm timer.
+  int alarm_fd_;
+
+  // Task runner which initially started the timer.
+  scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
+
+  // Callback that should be run when the timer fires.
+  base::Closure on_timer_fired_callback_;
+
+  // Hook used by tests to be notified when the timer has fired and a task has
+  // been queued in the MessageLoop.
+  base::Closure on_timer_fired_callback_for_test_;
+
+  // Manages watching file descriptors.
+  std::unique_ptr<base::MessageLoopForIO::FileDescriptorWatcher> fd_watcher_;
+
+  // The sequence numbers of the last Reset() call handled respectively on
+  // |origin_task_runner_| and on the MessageLoopForIO used for watching the
+  // timer file descriptor.  Note that these can be the same MessageLoop.
+  // OnTimerFired() runs |on_timer_fired_callback_| only if the sequence number
+  // it receives from the MessageLoopForIO matches
+  // |origin_reset_sequence_number_|.
+  int origin_reset_sequence_number_;
+  int io_reset_sequence_number_;
+
+  DISALLOW_COPY_AND_ASSIGN(Delegate);
+};
+
+AlarmTimer::Delegate::Delegate(base::Closure on_timer_fired_callback)
+    : alarm_fd_(timerfd_create(CLOCK_REALTIME_ALARM, 0)),
+      on_timer_fired_callback_(on_timer_fired_callback),
+      origin_reset_sequence_number_(0),
+      io_reset_sequence_number_(0) {
+  // The call to timerfd_create above may fail.  This is the only indication
+  // that CLOCK_REALTIME_ALARM is not supported on this system.
+  DPLOG_IF(INFO, (alarm_fd_ == -1))
+      << "CLOCK_REALTIME_ALARM not supported on this system";
+}
+
+AlarmTimer::Delegate::~Delegate() {
+  if (alarm_fd_ != -1)
+    close(alarm_fd_);
+}
+
+bool AlarmTimer::Delegate::CanWakeFromSuspend() {
+  return alarm_fd_ != -1;
+}
+
+void AlarmTimer::Delegate::Reset(base::TimeDelta delay) {
+  // Get a task runner for the current message loop.  When the timer fires, we
+  // will
+  // post tasks to this proxy to let the parent timer know.
+  origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+
+  // Increment the sequence number.  Used to invalidate any events that have
+  // been queued but not yet run since the last time Reset() was called.
+  origin_reset_sequence_number_++;
+
+  // Calling timerfd_settime with a zero delay actually clears the timer so if
+  // the user has requested a zero delay timer, we need to handle it
+  // differently.  We queue the task here but we still go ahead and call
+  // timerfd_settime with the zero delay anyway to cancel any previous delay
+  // that might have been programmed.
+  if (delay <= base::TimeDelta::FromMicroseconds(0)) {
+    // The timerfd_settime documentation is vague on what happens when it is
+    // passed a negative delay.  We can sidestep the issue by ensuring that
+    // the delay is 0.
+    delay = base::TimeDelta::FromMicroseconds(0);
+    origin_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this),
+                   origin_reset_sequence_number_));
+  }
+
+  // Run ResetImpl() on a MessageLoopForIO.
+  if (base::MessageLoopForIO::IsCurrent()) {
+    ResetImpl(delay, origin_reset_sequence_number_);
+  } else {
+    g_io_thread.Pointer()->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&Delegate::ResetImpl, scoped_refptr<Delegate>(this), delay,
+                   origin_reset_sequence_number_));
+  }
+}
+
+void AlarmTimer::Delegate::Stop() {
+  // Stop the RTC from a MessageLoopForIO.
+  if (!base::MessageLoopForIO::IsCurrent()) {
+    g_io_thread.Pointer()->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&Delegate::Stop, scoped_refptr<Delegate>(this)));
+    return;
+  }
+
+  // Stop watching for events.
+  fd_watcher_.reset();
+
+  // Now clear the timer.
+  DCHECK_NE(alarm_fd_, -1);
+#if defined(ANDROID)
+  itimerspec blank_time;
+  memset(&blank_time, 0, sizeof(blank_time));
+#else
+  itimerspec blank_time = {};
+#endif  // defined(ANDROID)
+  if (timerfd_settime(alarm_fd_, 0, &blank_time, NULL) < 0)
+    PLOG(ERROR) << "Unable to clear alarm time.  Timer may still fire.";
+}
+
+void AlarmTimer::Delegate::OnFileCanReadWithoutBlocking(int fd) {
+  DCHECK_EQ(alarm_fd_, fd);
+
+  // Read from the fd to ack the event.
+  char val[sizeof(uint64_t)];
+  if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t)))
+    PLOG(DFATAL) << "Unable to read from timer file descriptor.";
+
+  // Make sure that the parent timer is informed on the proper message loop.
+  if (origin_task_runner_->RunsTasksOnCurrentThread()) {
+    OnTimerFired(io_reset_sequence_number_);
+  } else {
+    origin_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this),
+                   io_reset_sequence_number_));
+  }
+}
+
+void AlarmTimer::Delegate::OnFileCanWriteWithoutBlocking(int /*fd*/) {
+  NOTREACHED();
+}
+
+void AlarmTimer::Delegate::SetTimerFiredCallbackForTest(
+    base::Closure test_callback) {
+  on_timer_fired_callback_for_test_ = test_callback;
+}
+
+void AlarmTimer::Delegate::ResetImpl(base::TimeDelta delay,
+                                     int reset_sequence_number) {
+  DCHECK(base::MessageLoopForIO::IsCurrent());
+  DCHECK_NE(alarm_fd_, -1);
+
+  // Store the sequence number in the IO thread variable.  When the timer
+  // fires, we will bind this value to the OnTimerFired callback to ensure
+  // that we do the right thing if the timer gets reset.
+  io_reset_sequence_number_ = reset_sequence_number;
+
+  // If we were already watching the fd, this will stop watching it.
+  fd_watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher);
+
+  // Start watching the fd to see when the timer fires.
+  if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
+          alarm_fd_, false, base::MessageLoopForIO::WATCH_READ,
+          fd_watcher_.get(), this)) {
+    LOG(ERROR) << "Error while attempting to watch file descriptor for RTC "
+               << "alarm.  Timer will not fire.";
+  }
+
+  // Actually set the timer.  This will also clear the pre-existing timer, if
+  // any.
+#if defined(ANDROID)
+  itimerspec alarm_time;
+  memset(&alarm_time, 0, sizeof(alarm_time));
+#else
+  itimerspec alarm_time = {};
+#endif  // defined(ANDROID)
+  alarm_time.it_value.tv_sec = delay.InSeconds();
+  alarm_time.it_value.tv_nsec =
+      (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) *
+      base::Time::kNanosecondsPerMicrosecond;
+  if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0)
+    PLOG(ERROR) << "Error while setting alarm time.  Timer will not fire";
+}
+
+void AlarmTimer::Delegate::OnTimerFired(int reset_sequence_number) {
+  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
+
+  // If a test wants to be notified when this function is about to run, then
+  // re-queue this task in the MessageLoop and run the test's callback.
+  if (!on_timer_fired_callback_for_test_.is_null()) {
+    origin_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this),
+                   reset_sequence_number));
+
+    on_timer_fired_callback_for_test_.Run();
+    on_timer_fired_callback_for_test_.Reset();
+    return;
+  }
+
+  // Check to make sure that the timer was not reset in the time between when
+  // this task was queued to run and now.  If it was reset, then don't do
+  // anything.
+  if (reset_sequence_number != origin_reset_sequence_number_)
+    return;
+
+  on_timer_fired_callback_.Run();
+}
+
+AlarmTimer::AlarmTimer(bool retain_user_task, bool is_repeating)
+    : base::Timer(retain_user_task, is_repeating),
+      can_wake_from_suspend_(false),
+      origin_message_loop_(NULL),
+      weak_factory_(this) {
+  Init();
+}
+
+AlarmTimer::AlarmTimer(const tracked_objects::Location& posted_from,
+                       base::TimeDelta delay,
+                       const base::Closure& user_task,
+                       bool is_repeating)
+    : base::Timer(posted_from, delay, user_task, is_repeating),
+      can_wake_from_suspend_(false),
+      origin_message_loop_(NULL),
+      weak_factory_(this) {
+  Init();
+}
+
+AlarmTimer::~AlarmTimer() {
+  Stop();
+}
+
+void AlarmTimer::SetTimerFiredCallbackForTest(base::Closure test_callback) {
+  delegate_->SetTimerFiredCallbackForTest(test_callback);
+}
+
+void AlarmTimer::Init() {
+  delegate_ = make_scoped_refptr(new AlarmTimer::Delegate(
+      base::Bind(&AlarmTimer::OnTimerFired, weak_factory_.GetWeakPtr())));
+  can_wake_from_suspend_ = delegate_->CanWakeFromSuspend();
+}
+
+void AlarmTimer::Stop() {
+  if (!base::Timer::is_running())
+    return;
+
+  if (!can_wake_from_suspend_) {
+    base::Timer::Stop();
+    return;
+  }
+
+  // Clear the running flag, stop the delegate, and delete the pending task.
+  base::Timer::set_is_running(false);
+  delegate_->Stop();
+  pending_task_.reset();
+
+  // Stop watching |origin_message_loop_|.
+  origin_message_loop_ = NULL;
+  message_loop_observer_.reset();
+
+  if (!base::Timer::retain_user_task())
+    base::Timer::set_user_task(base::Closure());
+}
+
+void AlarmTimer::Reset() {
+  if (!can_wake_from_suspend_) {
+    base::Timer::Reset();
+    return;
+  }
+
+  DCHECK(!base::Timer::user_task().is_null());
+  DCHECK(!origin_message_loop_ ||
+         origin_message_loop_->task_runner()->RunsTasksOnCurrentThread());
+
+  // Make sure that the timer will stop if the underlying message loop is
+  // destroyed.
+  if (!origin_message_loop_) {
+    origin_message_loop_ = base::MessageLoop::current();
+    message_loop_observer_.reset(new MessageLoopObserver(
+        origin_message_loop_,
+        base::Bind(&AlarmTimer::WillDestroyCurrentMessageLoop,
+                   weak_factory_.GetWeakPtr())));
+  }
+
+  // Set up the pending task.
+  if (base::Timer::GetCurrentDelay() > base::TimeDelta::FromMicroseconds(0)) {
+    base::Timer::set_desired_run_time(base::TimeTicks::Now() +
+                                      base::Timer::GetCurrentDelay());
+    pending_task_.reset(new base::PendingTask(
+        base::Timer::posted_from(), base::Timer::user_task(),
+        base::Timer::desired_run_time(), true /* nestable */));
+  } else {
+    base::Timer::set_desired_run_time(base::TimeTicks());
+    pending_task_.reset(new base::PendingTask(base::Timer::posted_from(),
+                                              base::Timer::user_task()));
+  }
+  base::MessageLoop::current()->task_annotator()->DidQueueTask(
+      "AlarmTimer::Reset", *pending_task_);
+
+  // Now start up the timer.
+  delegate_->Reset(base::Timer::GetCurrentDelay());
+  base::Timer::set_is_running(true);
+}
+
+void AlarmTimer::WillDestroyCurrentMessageLoop() {
+  Stop();
+}
+
+void AlarmTimer::OnTimerFired() {
+  if (!base::Timer::IsRunning())
+    return;
+
+  DCHECK(pending_task_.get());
+
+  // Take ownership of the pending user task, which is going to be cleared by
+  // the Stop() or Reset() functions below.
+  std::unique_ptr<base::PendingTask> pending_user_task(
+      std::move(pending_task_));
+
+  // Re-schedule or stop the timer as requested.
+  if (base::Timer::is_repeating())
+    Reset();
+  else
+    Stop();
+
+  TRACE_TASK_EXECUTION("AlarmTimer::OnTimerFired", *pending_user_task);
+
+  // Now run the user task.
+  base::MessageLoop::current()->task_annotator()->RunTask("AlarmTimer::Reset",
+                                                          *pending_user_task);
+}
+
+OneShotAlarmTimer::OneShotAlarmTimer() : AlarmTimer(false, false) {
+}
+
+OneShotAlarmTimer::~OneShotAlarmTimer() {
+}
+
+RepeatingAlarmTimer::RepeatingAlarmTimer() : AlarmTimer(true, true) {
+}
+
+RepeatingAlarmTimer::RepeatingAlarmTimer(
+    const tracked_objects::Location& posted_from,
+    base::TimeDelta delay,
+    const base::Closure& user_task)
+    : AlarmTimer(posted_from, delay, user_task, true) {
+}
+
+RepeatingAlarmTimer::~RepeatingAlarmTimer() {
+}
+
+SimpleAlarmTimer::SimpleAlarmTimer() : AlarmTimer(true, false) {
+}
+
+SimpleAlarmTimer::SimpleAlarmTimer(const tracked_objects::Location& posted_from,
+                                   base::TimeDelta delay,
+                                   const base::Closure& user_task)
+    : AlarmTimer(posted_from, delay, user_task, false) {
+}
+
+SimpleAlarmTimer::~SimpleAlarmTimer() {
+}
+
+}  // namespace timers
diff --git a/libchrome/components/timers/alarm_timer_chromeos.h b/libchrome/components/timers/alarm_timer_chromeos.h
new file mode 100644
index 0000000..313c9f9
--- /dev/null
+++ b/libchrome/components/timers/alarm_timer_chromeos.h
@@ -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.
+
+#ifndef COMPONENTS_TIMERS_ALARM_TIMER_CHROMEOS_H_
+#define COMPONENTS_TIMERS_ALARM_TIMER_CHROMEOS_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace base {
+class MessageLoop;
+struct PendingTask;
+}
+
+namespace timers {
+// The class implements a timer that is capable of waking the system up from a
+// suspended state.  For example, this is useful for running tasks that are
+// needed for maintaining network connectivity, like sending heartbeat messages.
+// Currently, this feature is only available on Chrome OS systems running linux
+// version 3.11 or higher.  On all other platforms, the AlarmTimer behaves
+// exactly the same way as a regular Timer.
+class AlarmTimer : public base::Timer {
+ public:
+  ~AlarmTimer() override;
+
+  bool can_wake_from_suspend() const { return can_wake_from_suspend_; }
+
+  // Sets a hook that will be called when the timer fires and a task has been
+  // queued on |origin_message_loop_|.  Used by tests to wait until a task is
+  // pending in the MessageLoop.
+  void SetTimerFiredCallbackForTest(base::Closure test_callback);
+
+  // Timer overrides.
+  void Stop() override;
+  void Reset() override;
+
+ protected:
+  // The constructors for this class are protected because consumers should
+  // instantiate one of the specialized sub-classes defined below instead.
+  AlarmTimer(bool retain_user_task, bool is_repeating);
+  AlarmTimer(const tracked_objects::Location& posted_from,
+             base::TimeDelta delay,
+             const base::Closure& user_task,
+             bool is_repeating);
+
+ private:
+  // Common initialization that must be performed by both constructors.  This
+  // really should live in a delegated constructor but the way base::Timer's
+  // constructors are written makes it really hard to do so.
+  void Init();
+
+  // Will be called by the delegate to indicate that the timer has fired and
+  // that the user task should be run.
+  void OnTimerFired();
+
+  // Called when |origin_message_loop_| will be destroyed.
+  void WillDestroyCurrentMessageLoop();
+
+  // Delegate that will manage actually setting the timer.
+  class Delegate;
+  scoped_refptr<Delegate> delegate_;
+
+  // Keeps track of the user task we want to run.  A new one is constructed
+  // every time Reset() is called.
+  std::unique_ptr<base::PendingTask> pending_task_;
+
+  // Tracks whether the timer has the ability to wake the system up from
+  // suspend.  This is a runtime check because we won't know if the system
+  // supports being woken up from suspend until the delegate actually tries to
+  // set it up.
+  bool can_wake_from_suspend_;
+
+  // Pointer to the message loop that started the timer.  Used to track the
+  // destruction of that message loop.
+  base::MessageLoop* origin_message_loop_;
+
+  // Observes |origin_message_loop_| and informs this class if it will be
+  // destroyed.
+  class MessageLoopObserver;
+  std::unique_ptr<MessageLoopObserver> message_loop_observer_;
+
+  base::WeakPtrFactory<AlarmTimer> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AlarmTimer);
+};
+
+// As its name suggests, a OneShotAlarmTimer runs a given task once.  It does
+// not remember the task that was given to it after it has fired and does not
+// repeat.  Useful for fire-and-forget tasks.
+class OneShotAlarmTimer : public AlarmTimer {
+ public:
+  // Constructs a basic OneShotAlarmTimer.  An AlarmTimer constructed this way
+  // requires that Start() is called before Reset() is called.
+  OneShotAlarmTimer();
+  ~OneShotAlarmTimer() override;
+};
+
+// A RepeatingAlarmTimer takes a task and delay and repeatedly runs the task
+// using the specified delay as an interval between the runs until it is
+// explicitly stopped.  It remembers both the task and the delay it was given
+// after it fires.
+class RepeatingAlarmTimer : public AlarmTimer {
+ public:
+  // Constructs a basic RepeatingAlarmTimer.  An AlarmTimer constructed this way
+  // requires that Start() is called before Reset() is called.
+  RepeatingAlarmTimer();
+
+  // Constructs a RepeatingAlarmTimer with pre-populated parameters but does not
+  // start it.  Useful if |user_task| or |delay| are not going to change.
+  // Reset() can be called immediately after constructing an AlarmTimer in this
+  // way.
+  RepeatingAlarmTimer(const tracked_objects::Location& posted_from,
+                      base::TimeDelta delay,
+                      const base::Closure& user_task);
+
+  ~RepeatingAlarmTimer() override;
+};
+
+// A SimpleAlarmTimer only fires once but remembers the task that it was given
+// even after it has fired.  Useful if you want to run the same task multiple
+// times but not at a regular interval.
+class SimpleAlarmTimer : public AlarmTimer {
+ public:
+  // Constructs a basic SimpleAlarmTimer.  An AlarmTimer constructed this way
+  // requires that Start() is called before Reset() is called.
+  SimpleAlarmTimer();
+
+  // Constructs a SimpleAlarmTimer with pre-populated parameters but does not
+  // start it.  Useful if |user_task| or |delay| are not going to change.
+  // Reset() can be called immediately after constructing an AlarmTimer in this
+  // way.
+  SimpleAlarmTimer(const tracked_objects::Location& posted_from,
+                   base::TimeDelta delay,
+                   const base::Closure& user_task);
+
+  ~SimpleAlarmTimer() override;
+};
+
+}  // namespace timers
+
+#endif  // COMPONENTS_TIMERS_ALARM_TIMER_CHROMEOS_H_
diff --git a/libchrome/crypto/BUILD.gn b/libchrome/crypto/BUILD.gn
new file mode 100644
index 0000000..a912d93
--- /dev/null
+++ b/libchrome/crypto/BUILD.gn
@@ -0,0 +1,228 @@
+# 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/crypto.gni")
+import("//testing/test.gni")
+
+component("crypto") {
+  output_name = "crcrypto"  # Avoid colliding with OpenSSL's libcrypto.
+  sources = [
+    "aead.cc",
+    "aead.h",
+    "apple_keychain.h",
+    "apple_keychain_ios.mm",
+    "apple_keychain_mac.mm",
+    "auto_cbb.h",
+    "capi_util.cc",
+    "capi_util.h",
+    "crypto_export.h",
+    "cssm_init.cc",
+    "cssm_init.h",
+    "curve25519.cc",
+    "curve25519.h",
+    "ec_private_key.cc",
+    "ec_private_key.h",
+    "ec_signature_creator.cc",
+    "ec_signature_creator.h",
+    "ec_signature_creator_impl.cc",
+    "ec_signature_creator_impl.h",
+    "encryptor.cc",
+    "encryptor.h",
+    "hkdf.cc",
+    "hkdf.h",
+    "hmac.cc",
+    "hmac.h",
+    "mac_security_services_lock.cc",
+    "mac_security_services_lock.h",
+
+    # TODO(brettw) these mocks should be moved to a test_support_crypto target
+    # if possible.
+    "mock_apple_keychain.cc",
+    "mock_apple_keychain.h",
+    "mock_apple_keychain_ios.cc",
+    "mock_apple_keychain_mac.cc",
+    "nss_key_util.cc",
+    "nss_key_util.h",
+    "nss_util.cc",
+    "nss_util.h",
+    "nss_util_internal.h",
+    "openssl_bio_string.cc",
+    "openssl_bio_string.h",
+    "openssl_util.cc",
+    "openssl_util.h",
+    "p224.cc",
+    "p224.h",
+    "p224_spake.cc",
+    "p224_spake.h",
+    "random.cc",
+    "random.h",
+    "rsa_private_key.cc",
+    "rsa_private_key.h",
+    "scoped_capi_types.h",
+    "scoped_nss_types.h",
+    "secure_hash.cc",
+    "secure_hash.h",
+    "secure_util.cc",
+    "secure_util.h",
+    "sha2.cc",
+    "sha2.h",
+    "signature_creator.cc",
+    "signature_creator.h",
+    "signature_verifier.cc",
+    "signature_verifier.h",
+    "symmetric_key.cc",
+    "symmetric_key.h",
+  ]
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  deps = [
+    ":platform",
+    "//base",
+    "//base/third_party/dynamic_annotations",
+  ]
+
+  if (!is_mac && !is_ios) {
+    sources -= [
+      "apple_keychain.h",
+      "mock_apple_keychain.cc",
+      "mock_apple_keychain.h",
+    ]
+  } else {
+    libs = [
+      "CoreFoundation.framework",
+      "Security.framework",
+    ]
+  }
+
+  if (!is_mac) {
+    sources -= [
+      "cssm_init.cc",
+      "cssm_init.h",
+      "mac_security_services_lock.cc",
+      "mac_security_services_lock.h",
+    ]
+  }
+  if (!is_win) {
+    sources -= [
+      "capi_util.cc",
+      "capi_util.h",
+    ]
+  }
+
+  # Some files are built when NSS is used for the platform certificate library.
+  if (!use_nss_certs) {
+    sources -= [
+      "nss_key_util.cc",
+      "nss_key_util.h",
+      "nss_util.cc",
+      "nss_util.h",
+      "nss_util_internal.h",
+    ]
+  }
+
+  defines = [ "CRYPTO_IMPLEMENTATION" ]
+
+  if (is_nacl) {
+    deps += [ "//native_client_sdk/src/libraries/nacl_io" ]
+  }
+}
+
+test("crypto_unittests") {
+  sources = [
+    "aead_unittest.cc",
+    "curve25519_unittest.cc",
+    "ec_private_key_unittest.cc",
+    "ec_signature_creator_unittest.cc",
+    "encryptor_unittest.cc",
+    "hkdf_unittest.cc",
+    "hmac_unittest.cc",
+    "nss_key_util_unittest.cc",
+    "nss_util_unittest.cc",
+    "openssl_bio_string_unittest.cc",
+    "p224_spake_unittest.cc",
+    "p224_unittest.cc",
+    "random_unittest.cc",
+    "rsa_private_key_unittest.cc",
+    "secure_hash_unittest.cc",
+    "sha2_unittest.cc",
+    "signature_creator_unittest.cc",
+    "signature_verifier_unittest.cc",
+    "symmetric_key_unittest.cc",
+  ]
+
+  # Some files are built when NSS is used for the platform certificate library.
+  if (!use_nss_certs) {
+    sources -= [
+      "nss_key_util_unittest.cc",
+      "nss_util_unittest.cc",
+    ]
+  }
+
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  deps = [
+    ":crypto",
+    ":platform",
+    ":test_support",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
+# This has no sources in some cases so can't be a static library.
+source_set("test_support") {
+  testonly = true
+  sources = []
+
+  if (use_nss_certs) {
+    sources += [
+      "scoped_test_nss_db.cc",
+      "scoped_test_nss_db.h",
+    ]
+  }
+
+  if (is_chromeos) {
+    sources += [
+      "scoped_test_nss_chromeos_user.cc",
+      "scoped_test_nss_chromeos_user.h",
+      "scoped_test_system_nss_key_slot.cc",
+      "scoped_test_system_nss_key_slot.h",
+    ]
+  }
+
+  deps = [
+    ":crypto",
+    ":platform",
+    "//base",
+  ]
+}
+
+config("platform_config") {
+  if (use_nss_certs && is_clang) {
+    # There is a broken header guard in /usr/include/nss/secmod.h:
+    # https://bugzilla.mozilla.org/show_bug.cgi?id=884072
+    cflags = [ "-Wno-header-guard" ]
+  }
+}
+
+# This is a meta-target that forwards to NSS's SSL library or OpenSSL,
+# according to the state of the crypto flags. A target just wanting to depend
+# on the current SSL library should just depend on this.
+group("platform") {
+  public_deps = [
+    "//third_party/boringssl",
+  ]
+
+  # Link in NSS if it is used for the platform certificate library
+  # (use_nss_certs).
+  if (use_nss_certs) {
+    public_configs = [ ":platform_config" ]
+    public_configs += [ "//third_party/nss:system_nss_no_ssl_config" ]
+  }
+}
diff --git a/libchrome/crypto/OWNERS b/libchrome/crypto/OWNERS
new file mode 100644
index 0000000..42d0d3b
--- /dev/null
+++ b/libchrome/crypto/OWNERS
@@ -0,0 +1,3 @@
+agl@chromium.org
+davidben@chromium.org
+rsleevi@chromium.org
diff --git a/libchrome/crypto/apple_keychain.h b/libchrome/crypto/apple_keychain.h
new file mode 100644
index 0000000..1ea2473
--- /dev/null
+++ b/libchrome/crypto/apple_keychain.h
@@ -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.
+
+#ifndef CRYPTO_KEYCHAIN_MAC_H_
+#define CRYPTO_KEYCHAIN_MAC_H_
+
+#include <Security/Security.h>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+
+#if defined (OS_IOS)
+typedef void* SecKeychainRef;
+typedef void* SecKeychainItemRef;
+typedef void SecKeychainAttributeList;
+#endif
+
+namespace crypto {
+
+// Wraps the KeychainServices API in a very thin layer, to allow it to be
+// mocked out for testing.
+
+// See Keychain Services documentation for function documentation, as these call
+// through directly to their Keychain Services equivalents (Foo ->
+// SecKeychainFoo). The only exception is Free, which should be used for
+// anything returned from this class that would normally be freed with
+// CFRelease (to aid in testing).
+class CRYPTO_EXPORT AppleKeychain {
+ public:
+  AppleKeychain();
+  virtual ~AppleKeychain();
+
+  virtual OSStatus FindGenericPassword(CFTypeRef keychainOrArray,
+                                       UInt32 serviceNameLength,
+                                       const char* serviceName,
+                                       UInt32 accountNameLength,
+                                       const char* accountName,
+                                       UInt32* passwordLength,
+                                       void** passwordData,
+                                       SecKeychainItemRef* itemRef) const;
+
+  virtual OSStatus ItemFreeContent(SecKeychainAttributeList* attrList,
+                                   void* data) const;
+
+  virtual OSStatus AddGenericPassword(SecKeychainRef keychain,
+                                      UInt32 serviceNameLength,
+                                      const char* serviceName,
+                                      UInt32 accountNameLength,
+                                      const char* accountName,
+                                      UInt32 passwordLength,
+                                      const void* passwordData,
+                                      SecKeychainItemRef* itemRef) const;
+
+#if !defined(OS_IOS)
+  virtual OSStatus ItemCopyAttributesAndData(
+      SecKeychainItemRef itemRef,
+      SecKeychainAttributeInfo* info,
+      SecItemClass* itemClass,
+      SecKeychainAttributeList** attrList,
+      UInt32* length,
+      void** outData) const;
+
+  virtual OSStatus ItemModifyAttributesAndData(
+      SecKeychainItemRef itemRef,
+      const SecKeychainAttributeList* attrList,
+      UInt32 length,
+      const void* data) const;
+
+  virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList,
+                                             void* data) const;
+
+  virtual OSStatus ItemDelete(SecKeychainItemRef itemRef) const;
+
+  virtual OSStatus SearchCreateFromAttributes(
+      CFTypeRef keychainOrArray,
+      SecItemClass itemClass,
+      const SecKeychainAttributeList* attrList,
+      SecKeychainSearchRef* searchRef) const;
+
+  virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
+                                  SecKeychainItemRef* itemRef) const;
+
+  virtual OSStatus AddInternetPassword(SecKeychainRef keychain,
+                                       UInt32 serverNameLength,
+                                       const char* serverName,
+                                       UInt32 securityDomainLength,
+                                       const char* securityDomain,
+                                       UInt32 accountNameLength,
+                                       const char* accountName,
+                                       UInt32 pathLength, const char* path,
+                                       UInt16 port, SecProtocolType protocol,
+                                       SecAuthenticationType authenticationType,
+                                       UInt32 passwordLength,
+                                       const void* passwordData,
+                                       SecKeychainItemRef* itemRef) const;
+
+  // Calls CFRelease on the given ref, after checking that |ref| is non-NULL.
+  virtual void Free(CFTypeRef ref) const;
+#endif  // !defined(OS_IOS)
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AppleKeychain);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_KEYCHAIN_MAC_H_
diff --git a/libchrome/crypto/auto_cbb.h b/libchrome/crypto/auto_cbb.h
new file mode 100644
index 0000000..5206a21
--- /dev/null
+++ b/libchrome/crypto/auto_cbb.h
@@ -0,0 +1,35 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_AUTO_CBB_H_
+#define CRYPTO_AUTO_CBB_H_
+
+#include <openssl/bytestring.h>
+
+#include "base/macros.h"
+
+namespace crypto {
+
+// AutoCBB is a wrapper over OpenSSL's CBB type that automatically releases
+// resources when going out of scope.
+class AutoCBB {
+ public:
+  AutoCBB() { CBB_zero(&cbb_); }
+  ~AutoCBB() { CBB_cleanup(&cbb_); }
+
+  CBB* get() { return &cbb_; }
+
+  void Reset() {
+    CBB_cleanup(&cbb_);
+    CBB_zero(&cbb_);
+  }
+
+ private:
+  CBB cbb_;
+  DISALLOW_COPY_AND_ASSIGN(AutoCBB);
+};
+
+}  // namespace crypto
+
+#endif   // CRYPTO_AUTO_CBB_H_
diff --git a/libchrome/crypto/crypto.gyp b/libchrome/crypto/crypto.gyp
new file mode 100644
index 0000000..8ed2ab2
--- /dev/null
+++ b/libchrome/crypto/crypto.gyp
@@ -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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    'crypto.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'crypto',
+      'type': '<(component)',
+      'product_name': 'crcrypto',  # Avoid colliding with OpenSSL's libcrypto
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../third_party/boringssl/boringssl.gyp:boringssl',
+      ],
+      'defines': [
+        'CRYPTO_IMPLEMENTATION',
+      ],
+      'conditions': [
+        [ 'os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
+          'dependencies': [
+            '../build/linux/system.gyp:nss',
+          ],
+          'export_dependent_settings': [
+            '../build/linux/system.gyp:nss',
+          ],
+          'conditions': [
+            [ 'chromeos==1', {
+                'sources/': [ ['include', '_chromeos\\.cc$'] ]
+              },
+            ],
+          ],
+        }],
+        [ 'OS != "mac" and OS != "ios"', {
+          'sources!': [
+            'apple_keychain.h',
+            'mock_apple_keychain.cc',
+            'mock_apple_keychain.h',
+          ],
+        }],
+        [ 'os_bsd==1', {
+          'link_settings': {
+            'libraries': [
+              '-L/usr/local/lib -lexecinfo',
+              ],
+            },
+          },
+        ],
+        [ 'OS == "mac"', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/Security.framework',
+            ],
+          },
+        }, {  # OS != "mac"
+          'sources!': [
+            'cssm_init.cc',
+            'cssm_init.h',
+            'mac_security_services_lock.cc',
+            'mac_security_services_lock.h',
+          ],
+        }],
+        [ 'OS != "win"', {
+          'sources!': [
+            'capi_util.h',
+            'capi_util.cc',
+          ],
+        }],
+        [ 'OS == "win"', {
+          'msvs_disabled_warnings': [
+            4267,  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          ],
+        }],
+        [ 'use_nss_certs==0', {
+            # Some files are built when NSS is used for the platform certificate library.
+            'sources!': [
+              'nss_key_util.cc',
+              'nss_key_util.h',
+              'nss_util.cc',
+              'nss_util.h',
+              'nss_util_internal.h',
+            ],
+        },],
+      ],
+      'sources': [
+        '<@(crypto_sources)',
+      ],
+    },
+    {
+      'target_name': 'crypto_unittests',
+      'type': 'executable',
+      'sources': [
+        'aead_unittest.cc',
+        'curve25519_unittest.cc',
+        'ec_private_key_unittest.cc',
+        'ec_signature_creator_unittest.cc',
+        'encryptor_unittest.cc',
+        'hkdf_unittest.cc',
+        'hmac_unittest.cc',
+        'nss_key_util_unittest.cc',
+        'nss_util_unittest.cc',
+        'openssl_bio_string_unittest.cc',
+        'p224_unittest.cc',
+        'p224_spake_unittest.cc',
+        'random_unittest.cc',
+        'rsa_private_key_unittest.cc',
+        'secure_hash_unittest.cc',
+        'sha2_unittest.cc',
+        'signature_creator_unittest.cc',
+        'signature_verifier_unittest.cc',
+        'symmetric_key_unittest.cc',
+      ],
+      'dependencies': [
+        'crypto',
+        'crypto_test_support',
+        '../base/base.gyp:base',
+        '../base/base.gyp:run_all_unittests',
+        '../base/base.gyp:test_support_base',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../third_party/boringssl/boringssl.gyp:boringssl',
+      ],
+      'conditions': [
+        [ 'use_nss_certs == 1', {
+          'dependencies': [
+            '../build/linux/system.gyp:nss',
+          ],
+        }],
+        [ 'use_nss_certs == 0', {
+          # Some files are built when NSS is used for the platform certificate library.
+          'sources!': [
+            'nss_key_util_unittest.cc',
+            'nss_util_unittest.cc',
+          ],
+        }],
+        [ 'OS == "win"', {
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [4267, ],
+        }],
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS == "win" and target_arch=="ia32"', {
+      'targets': [
+        {
+          'target_name': 'crypto_nacl_win64',
+          # We use the native APIs for the helper.
+          'type': '<(component)',
+          'dependencies': [
+            '../base/base.gyp:base_win64',
+            '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+            '../third_party/boringssl/boringssl.gyp:boringssl_nacl_win64',
+          ],
+          'sources': [
+            '<@(nacl_win64_sources)',
+          ],
+          'defines': [
+           'CRYPTO_IMPLEMENTATION',
+           '<@(nacl_win64_defines)',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      ],
+    }],
+    ['use_nss_certs==1', {
+      'targets': [
+        {
+          'target_name': 'crypto_test_support',
+          'type': 'static_library',
+          'dependencies': [
+            '../base/base.gyp:base',
+            'crypto',
+          ],
+          'sources': [
+            'scoped_test_nss_db.cc',
+            'scoped_test_nss_db.h',
+            'scoped_test_nss_chromeos_user.cc',
+            'scoped_test_nss_chromeos_user.h',
+            'scoped_test_system_nss_key_slot.cc',
+            'scoped_test_system_nss_key_slot.h',
+          ],
+          'conditions': [
+            ['use_nss_certs==0', {
+              'sources!': [
+                'scoped_test_nss_db.cc',
+                'scoped_test_nss_db.h',
+              ],
+            }],
+            [ 'chromeos==0', {
+              'sources!': [
+                'scoped_test_nss_chromeos_user.cc',
+                'scoped_test_nss_chromeos_user.h',
+                'scoped_test_system_nss_key_slot.cc',
+                'scoped_test_system_nss_key_slot.h',
+              ],
+            }],
+          ],
+        }
+      ]}, {  # use_nss_certs==0
+      'targets': [
+        {
+          'target_name': 'crypto_test_support',
+          'type': 'none',
+          'sources': [],
+        }
+    ]}],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'crypto_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'crypto_unittests',
+          ],
+          'includes': [
+            '../build/isolate.gypi',
+                      ],
+          'sources': [
+            'crypto_unittests.isolate',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/crypto/crypto.gypi b/libchrome/crypto/crypto.gypi
new file mode 100644
index 0000000..dadc0ea
--- /dev/null
+++ b/libchrome/crypto/crypto.gypi
@@ -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.
+
+{
+  'variables': {
+    # Put all transitive dependencies for Windows HMAC here.
+    # This is required so that we can build them for nacl win64.
+    'variables': {
+      'hmac_win64_related_sources': [
+        'crypto_export.h',
+        'hmac.cc',
+        'hmac.h',
+        'openssl_util.cc',
+        'openssl_util.h',
+        'secure_util.cc',
+        'secure_util.h',
+        'symmetric_key.cc',
+        'symmetric_key.h',
+      ],
+    },
+    'crypto_sources': [
+      # NOTE: all transitive dependencies of HMAC on windows need
+      #     to be placed in the source list above.
+      '<@(hmac_win64_related_sources)',
+      'aead.cc',
+      'aead.h',
+      'apple_keychain.h',
+      'apple_keychain_ios.mm',
+      'apple_keychain_mac.mm',
+      'auto_cbb.h',
+      'capi_util.cc',
+      'capi_util.h',
+      'cssm_init.cc',
+      'cssm_init.h',
+      'curve25519.cc',
+      'curve25519.h',
+      'ec_private_key.cc',
+      'ec_private_key.h',
+      'ec_signature_creator.cc',
+      'ec_signature_creator.h',
+      'ec_signature_creator_impl.cc',
+      'ec_signature_creator_impl.h',
+      'encryptor.cc',
+      'encryptor.h',
+      'hkdf.cc',
+      'hkdf.h',
+      'mac_security_services_lock.cc',
+      'mac_security_services_lock.h',
+      'mock_apple_keychain.cc',
+      'mock_apple_keychain.h',
+      'mock_apple_keychain_ios.cc',
+      'mock_apple_keychain_mac.cc',
+      'p224_spake.cc',
+      'p224_spake.h',
+      'nss_crypto_module_delegate.h',
+      'nss_key_util.cc',
+      'nss_key_util.h',
+      'nss_util.cc',
+      'nss_util.h',
+      'nss_util_internal.h',
+      'openssl_bio_string.cc',
+      'openssl_bio_string.h',
+      'p224.cc',
+      'p224.h',
+      'random.h',
+      'random.cc',
+      'rsa_private_key.cc',
+      'rsa_private_key.h',
+      'scoped_capi_types.h',
+      'scoped_nss_types.h',
+      'secure_hash.cc',
+      'secure_hash.h',
+      'sha2.cc',
+      'sha2.h',
+      'signature_creator.cc',
+      'signature_creator.h',
+      'signature_verifier.cc',
+      'signature_verifier.h',
+      'wincrypt_shim.h',
+    ],
+    'nacl_win64_sources': [
+      '<@(hmac_win64_related_sources)',
+      'random.cc',
+      'random.h',
+    ],
+  }
+}
diff --git a/libchrome/crypto/crypto_export.h b/libchrome/crypto/crypto_export.h
new file mode 100644
index 0000000..605af94
--- /dev/null
+++ b/libchrome/crypto/crypto_export.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 CRYPTO_CRYPTO_EXPORT_H_
+#define CRYPTO_CRYPTO_EXPORT_H_
+
+// Defines CRYPTO_EXPORT so that functionality implemented by the crypto module
+// can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(CRYPTO_IMPLEMENTATION)
+#define CRYPTO_EXPORT __declspec(dllexport)
+#else
+#define CRYPTO_EXPORT __declspec(dllimport)
+#endif  // defined(CRYPTO_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(CRYPTO_IMPLEMENTATION)
+#define CRYPTO_EXPORT __attribute__((visibility("default")))
+#else
+#define CRYPTO_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define CRYPTO_EXPORT
+#endif
+
+#endif  // CRYPTO_CRYPTO_EXPORT_H_
diff --git a/libchrome/crypto/crypto_nacl.gyp b/libchrome/crypto/crypto_nacl.gyp
new file mode 100644
index 0000000..c7c01a8
--- /dev/null
+++ b/libchrome/crypto/crypto_nacl.gyp
@@ -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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../native_client/build/untrusted.gypi',
+    'crypto.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'crypto_nacl',
+      'type': 'none',
+      'variables': {
+        'nacl_untrusted_build': 1,
+        'nlib_target': 'libcrypto_nacl.a',
+        'build_glibc': 0,
+        'build_newlib': 0,
+        'build_pnacl_newlib': 1,
+      },
+      'dependencies': [
+        '../third_party/boringssl/boringssl_nacl.gyp:boringssl_nacl',
+        '../native_client_sdk/native_client_sdk_untrusted.gyp:nacl_io_untrusted',
+      ],
+      'defines': [
+        'CRYPTO_IMPLEMENTATION',
+      ],
+      'sources': [
+        '<@(crypto_sources)',
+      ],
+      'sources/': [
+        ['exclude', '_nss\.(cc|h)$'],
+        ['exclude', '^(mock_)?apple_'],
+        ['exclude', '^capi_'],
+        ['exclude', '^cssm_'],
+        ['exclude', '^nss_'],
+        ['exclude', '^mac_'],
+      ],
+    },
+  ],
+}
diff --git a/libchrome/crypto/crypto_unittests.isolate b/libchrome/crypto/crypto_unittests.isolate
new file mode 100644
index 0000000..de13aa2
--- /dev/null
+++ b/libchrome/crypto/crypto_unittests.isolate
@@ -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.
+{
+  'variables': {
+    'command': [
+      '../testing/test_env.py',
+      '<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
+      '--brave-new-test-launcher',
+      '--test-launcher-bot-mode',
+      '--asan=<(asan)',
+      '--msan=<(msan)',
+      '--tsan=<(tsan)',
+    ],
+  },
+  'conditions': [
+    ['OS=="linux" or OS=="mac" or OS=="win"', {
+      'variables': {
+        'files': [
+          '../testing/test_env.py',
+        ],
+      },
+    }],
+    ['OS=="mac" and asan==1 and fastbuild==0', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/crypto_unittests.dSYM/',
+        ],
+      },
+    }],
+    ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/crypto_unittests.exe.pdb',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    '../base/base.isolate',
+  ],
+}
diff --git a/libchrome/crypto/ec_private_key.h b/libchrome/crypto/ec_private_key.h
new file mode 100644
index 0000000..a24219b
--- /dev/null
+++ b/libchrome/crypto/ec_private_key.h
@@ -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.
+
+#ifndef CRYPTO_EC_PRIVATE_KEY_H_
+#define CRYPTO_EC_PRIVATE_KEY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+
+#if defined(USE_OPENSSL)
+// Forward declaration for openssl/*.h
+typedef struct evp_pkey_st EVP_PKEY;
+#else
+// Forward declaration.
+typedef struct CERTSubjectPublicKeyInfoStr CERTSubjectPublicKeyInfo;
+typedef struct PK11SlotInfoStr PK11SlotInfo;
+typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey;
+typedef struct SECKEYPublicKeyStr SECKEYPublicKey;
+#endif
+
+namespace crypto {
+
+// Encapsulates an elliptic curve (EC) private key. Can be used to generate new
+// keys, export keys to other formats, or to extract a public key.
+// TODO(mattm): make this and RSAPrivateKey implement some PrivateKey interface.
+// (The difference in types of key() and public_key() make this a little
+// tricky.)
+class CRYPTO_EXPORT ECPrivateKey {
+ public:
+  ~ECPrivateKey();
+
+  // Creates a new random instance. Can return nullptr if initialization fails.
+  // The created key will use the NIST P-256 curve.
+  // TODO(mattm): Add a curve parameter.
+  static std::unique_ptr<ECPrivateKey> Create();
+
+  // Create a new instance by importing an existing private key. The format is
+  // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return
+  // nullptr if initialization fails.
+  static std::unique_ptr<ECPrivateKey> CreateFromPrivateKeyInfo(
+      const std::vector<uint8_t>& input);
+
+  // Creates a new instance by importing an existing key pair.
+  // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo
+  // block and an X.509 SubjectPublicKeyInfo block.
+  // Returns nullptr if initialization fails.
+  //
+  // This function is deprecated. Use CreateFromPrivateKeyInfo for new code.
+  // See https://crbug.com/603319.
+  static std::unique_ptr<ECPrivateKey> CreateFromEncryptedPrivateKeyInfo(
+      const std::string& password,
+      const std::vector<uint8_t>& encrypted_private_key_info,
+      const std::vector<uint8_t>& subject_public_key_info);
+
+#if !defined(USE_OPENSSL)
+  // Imports the key pair into |slot| and returns in |public_key| and |key|.
+  // Shortcut for code that needs to keep a reference directly to NSS types
+  // without having to create a ECPrivateKey object and make a copy of them.
+  // TODO(mattm): move this function to some NSS util file.
+  static bool ImportFromEncryptedPrivateKeyInfo(
+      PK11SlotInfo* slot,
+      const std::string& password,
+      const uint8_t* encrypted_private_key_info,
+      size_t encrypted_private_key_info_len,
+      CERTSubjectPublicKeyInfo* decoded_spki,
+      bool permanent,
+      bool sensitive,
+      SECKEYPrivateKey** key,
+      SECKEYPublicKey** public_key);
+#endif
+
+  // Returns a copy of the object.
+  std::unique_ptr<ECPrivateKey> Copy() const;
+
+#if defined(USE_OPENSSL)
+  EVP_PKEY* key() { return key_; }
+#else
+  SECKEYPrivateKey* key() { return key_; }
+  SECKEYPublicKey* public_key() { return public_key_; }
+#endif
+
+  // Exports the private key to a PKCS #8 PrivateKeyInfo block.
+  bool ExportPrivateKey(std::vector<uint8_t>* output) const;
+
+  // Exports the private key as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo
+  // block and the public key as an X.509 SubjectPublicKeyInfo block.
+  // The |password| and |iterations| are used as inputs to the key derivation
+  // function for generating the encryption key.  PKCS #5 recommends a minimum
+  // of 1000 iterations, on modern systems a larger value may be preferrable.
+  //
+  // This function is deprecated. Use ExportPrivateKey for new code. See
+  // https://crbug.com/603319.
+  bool ExportEncryptedPrivateKey(const std::string& password,
+                                 int iterations,
+                                 std::vector<uint8_t>* output) const;
+
+  // Exports the public key to an X.509 SubjectPublicKeyInfo block.
+  bool ExportPublicKey(std::vector<uint8_t>* output) const;
+
+  // Exports the public key as an EC point in the uncompressed point format.
+  bool ExportRawPublicKey(std::string* output) const;
+
+ private:
+  // Constructor is private. Use one of the Create*() methods above instead.
+  ECPrivateKey();
+
+#if defined(USE_OPENSSL)
+  EVP_PKEY* key_;
+#else
+  SECKEYPrivateKey* key_;
+  SECKEYPublicKey* public_key_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ECPrivateKey);
+};
+
+
+}  // namespace crypto
+
+#endif  // CRYPTO_EC_PRIVATE_KEY_H_
diff --git a/libchrome/crypto/ec_signature_creator_impl.h b/libchrome/crypto/ec_signature_creator_impl.h
new file mode 100644
index 0000000..21614f8
--- /dev/null
+++ b/libchrome/crypto/ec_signature_creator_impl.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 CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
+#define CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
+
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "crypto/ec_signature_creator.h"
+
+namespace crypto {
+
+class ECSignatureCreatorImpl : public ECSignatureCreator {
+ public:
+  explicit ECSignatureCreatorImpl(ECPrivateKey* key);
+  ~ECSignatureCreatorImpl() override;
+
+  bool Sign(const uint8_t* data,
+            int data_len,
+            std::vector<uint8_t>* signature) override;
+
+  bool DecodeSignature(const std::vector<uint8_t>& der_sig,
+                       std::vector<uint8_t>* out_raw_sig) override;
+
+ private:
+  ECPrivateKey* key_;
+
+  DISALLOW_COPY_AND_ASSIGN(ECSignatureCreatorImpl);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
diff --git a/libchrome/crypto/hmac.cc b/libchrome/crypto/hmac.cc
new file mode 100644
index 0000000..af5580b
--- /dev/null
+++ b/libchrome/crypto/hmac.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 "crypto/hmac.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "crypto/secure_util.h"
+#include "crypto/symmetric_key.h"
+
+namespace crypto {
+
+bool HMAC::Init(SymmetricKey* key) {
+  std::string raw_key;
+  bool result = key->GetRawKey(&raw_key) && Init(raw_key);
+  // Zero out key copy.  This might get optimized away, but one can hope.
+  // Using std::string to store key info at all is a larger problem.
+  std::fill(raw_key.begin(), raw_key.end(), 0);
+  return result;
+}
+
+size_t HMAC::DigestLength() const {
+  switch (hash_alg_) {
+    case SHA1:
+      return 20;
+    case SHA256:
+      return 32;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+bool HMAC::Verify(const base::StringPiece& data,
+                  const base::StringPiece& digest) const {
+  if (digest.size() != DigestLength())
+    return false;
+  return VerifyTruncated(data, digest);
+}
+
+bool HMAC::VerifyTruncated(const base::StringPiece& data,
+                           const base::StringPiece& digest) const {
+  if (digest.empty())
+    return false;
+  size_t digest_length = DigestLength();
+  std::unique_ptr<unsigned char[]> computed_digest(
+      new unsigned char[digest_length]);
+  if (!Sign(data, computed_digest.get(), digest_length))
+    return false;
+
+  return SecureMemEqual(digest.data(), computed_digest.get(),
+                        std::min(digest.size(), digest_length));
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/hmac.h b/libchrome/crypto/hmac.h
new file mode 100644
index 0000000..ec32ed7
--- /dev/null
+++ b/libchrome/crypto/hmac.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.
+
+// Utility class for calculating the HMAC for a given message. We currently
+// only support SHA1 for the hash algorithm, but this can be extended easily.
+
+#ifndef CRYPTO_HMAC_H_
+#define CRYPTO_HMAC_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Simplify the interface and reduce includes by abstracting out the internals.
+struct HMACPlatformData;
+class SymmetricKey;
+
+class CRYPTO_EXPORT HMAC {
+ public:
+  // The set of supported hash functions. Extend as required.
+  enum HashAlgorithm {
+    SHA1,
+    SHA256,
+  };
+
+  explicit HMAC(HashAlgorithm hash_alg);
+  ~HMAC();
+
+  // Returns the length of digest that this HMAC will create.
+  size_t DigestLength() const;
+
+  // TODO(abarth): Add a PreferredKeyLength() member function.
+
+  // Initializes this instance using |key| of the length |key_length|. Call Init
+  // only once. It returns false on the second or later calls.
+  //
+  // NOTE: the US Federal crypto standard FIPS 198, Section 3 says:
+  //   The size of the key, K, shall be equal to or greater than L/2, where L
+  //   is the size of the hash function output.
+  // In FIPS 198-1 (and SP-800-107, which describes key size recommendations),
+  // this requirement is gone.  But a system crypto library may still enforce
+  // this old requirement.  If the key is shorter than this recommended value,
+  // Init() may fail.
+  bool Init(const unsigned char* key, size_t key_length) WARN_UNUSED_RESULT;
+
+  // Initializes this instance using |key|. Call Init
+  // only once. It returns false on the second or later calls.
+  bool Init(SymmetricKey* key) WARN_UNUSED_RESULT;
+
+  // Initializes this instance using |key|. Call Init only once. It returns
+  // false on the second or later calls.
+  bool Init(const base::StringPiece& key) WARN_UNUSED_RESULT {
+    return Init(reinterpret_cast<const unsigned char*>(key.data()),
+                key.size());
+  }
+
+  // Calculates the HMAC for the message in |data| using the algorithm supplied
+  // to the constructor and the key supplied to the Init method. The HMAC is
+  // returned in |digest|, which has |digest_length| bytes of storage available.
+  bool Sign(const base::StringPiece& data, unsigned char* digest,
+            size_t digest_length) const WARN_UNUSED_RESULT;
+
+  // Verifies that the HMAC for the message in |data| equals the HMAC provided
+  // in |digest|, using the algorithm supplied to the constructor and the key
+  // supplied to the Init method. Use of this method is strongly recommended
+  // over using Sign() with a manual comparison (such as memcmp), as such
+  // comparisons may result in side-channel disclosures, such as timing, that
+  // undermine the cryptographic integrity. |digest| must be exactly
+  // |DigestLength()| bytes long.
+  bool Verify(const base::StringPiece& data,
+              const base::StringPiece& digest) const WARN_UNUSED_RESULT;
+
+  // Verifies a truncated HMAC, behaving identical to Verify(), except
+  // that |digest| is allowed to be smaller than |DigestLength()|.
+  bool VerifyTruncated(
+      const base::StringPiece& data,
+      const base::StringPiece& digest) const WARN_UNUSED_RESULT;
+
+ private:
+  HashAlgorithm hash_alg_;
+  std::unique_ptr<HMACPlatformData> plat_;
+
+  DISALLOW_COPY_AND_ASSIGN(HMAC);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_HMAC_H_
diff --git a/libchrome/crypto/hmac_nss.cc b/libchrome/crypto/hmac_nss.cc
new file mode 100644
index 0000000..9d759b5
--- /dev/null
+++ b/libchrome/crypto/hmac_nss.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 "crypto/hmac.h"
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace crypto {
+
+struct HMACPlatformData {
+  CK_MECHANISM_TYPE mechanism_;
+  ScopedPK11Slot slot_;
+  ScopedPK11SymKey sym_key_;
+};
+
+HMAC::HMAC(HashAlgorithm hash_alg)
+    : hash_alg_(hash_alg), plat_(new HMACPlatformData()) {
+  // Only SHA-1 and SHA-256 hash algorithms are supported.
+  switch (hash_alg_) {
+    case SHA1:
+      plat_->mechanism_ = CKM_SHA_1_HMAC;
+      break;
+    case SHA256:
+      plat_->mechanism_ = CKM_SHA256_HMAC;
+      break;
+    default:
+      NOTREACHED() << "Unsupported hash algorithm";
+      break;
+  }
+}
+
+HMAC::~HMAC() {
+}
+
+bool HMAC::Init(const unsigned char *key, size_t key_length) {
+  EnsureNSSInit();
+
+  if (plat_->slot_.get()) {
+    // Init must not be called more than twice on the same HMAC object.
+    NOTREACHED();
+    return false;
+  }
+
+  plat_->slot_.reset(PK11_GetInternalSlot());
+  if (!plat_->slot_.get()) {
+    NOTREACHED();
+    return false;
+  }
+
+  SECItem key_item;
+  key_item.type = siBuffer;
+  key_item.data = const_cast<unsigned char*>(key);  // NSS API isn't const.
+  key_item.len = key_length;
+
+  plat_->sym_key_.reset(PK11_ImportSymKey(plat_->slot_.get(),
+                                          plat_->mechanism_,
+                                          PK11_OriginUnwrap,
+                                          CKA_SIGN,
+                                          &key_item,
+                                          NULL));
+  if (!plat_->sym_key_.get()) {
+    NOTREACHED();
+    return false;
+  }
+
+  return true;
+}
+
+bool HMAC::Sign(const base::StringPiece& data,
+                unsigned char* digest,
+                size_t digest_length) const {
+  if (!plat_->sym_key_.get()) {
+    // Init has not been called before Sign.
+    NOTREACHED();
+    return false;
+  }
+
+  SECItem param = { siBuffer, NULL, 0 };
+  ScopedPK11Context context(PK11_CreateContextBySymKey(plat_->mechanism_,
+                                                       CKA_SIGN,
+                                                       plat_->sym_key_.get(),
+                                                       &param));
+  if (!context.get()) {
+    NOTREACHED();
+    return false;
+  }
+
+  if (PK11_DigestBegin(context.get()) != SECSuccess) {
+    NOTREACHED();
+    return false;
+  }
+
+  if (PK11_DigestOp(context.get(),
+                    reinterpret_cast<const unsigned char*>(data.data()),
+                    data.length()) != SECSuccess) {
+    NOTREACHED();
+    return false;
+  }
+
+  unsigned int len = 0;
+  if (PK11_DigestFinal(context.get(),
+                       digest, &len, digest_length) != SECSuccess) {
+    NOTREACHED();
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/hmac_unittest.cc b/libchrome/crypto/hmac_unittest.cc
new file mode 100644
index 0000000..9c42dad
--- /dev/null
+++ b/libchrome/crypto/hmac_unittest.cc
@@ -0,0 +1,298 @@
+// 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 <stddef.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "crypto/hmac.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+static const size_t kSHA1DigestSize = 20;
+static const size_t kSHA256DigestSize = 32;
+
+static const char* kSimpleKey =
+    "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+    "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+    "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+    "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+    "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
+static const size_t kSimpleKeyLength = 80;
+
+static const struct {
+  const char *data;
+  const int data_len;
+  const char *digest;
+} kSimpleHmacCases[] = {
+  { "Test Using Larger Than Block-Size Key - Hash Key First", 54,
+    "\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55"
+        "\xED\x40\x21\x12" },
+  { "Test Using Larger Than Block-Size Key and Larger "
+        "Than One Block-Size Data", 73,
+    "\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08"
+        "\xBB\xFF\x1A\x91" }
+};
+
+TEST(HMACTest, HmacSafeBrowsingResponseTest) {
+  const int kKeySize = 16;
+
+  // Client key.
+  const unsigned char kClientKey[kKeySize] =
+      { 0xbf, 0xf6, 0x83, 0x4b, 0x3e, 0xa3, 0x23, 0xdd,
+        0x96, 0x78, 0x70, 0x8e, 0xa1, 0x9d, 0x3b, 0x40 };
+
+  // Expected HMAC result using kMessage and kClientKey.
+  const unsigned char kReceivedHmac[kSHA1DigestSize] =
+      { 0xb9, 0x3c, 0xd6, 0xf0, 0x49, 0x47, 0xe2, 0x52,
+        0x59, 0x7a, 0xbd, 0x1f, 0x2b, 0x4c, 0x83, 0xad,
+        0x86, 0xd2, 0x48, 0x85 };
+
+  const char kMessage[] =
+"n:1896\ni:goog-malware-shavar\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shav"
+"ar_s_445-450\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_439-444\nu:s"
+".ytimg.com/safebrowsing/rd/goog-malware-shavar_s_437\nu:s.ytimg.com/safebrowsi"
+"ng/rd/goog-malware-shavar_s_436\nu:s.ytimg.com/safebrowsing/rd/goog-malware-sh"
+"avar_s_433-435\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_431\nu:s.y"
+"timg.com/safebrowsing/rd/goog-malware-shavar_s_430\nu:s.ytimg.com/safebrowsing"
+"/rd/goog-malware-shavar_s_429\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shav"
+"ar_s_428\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_426\nu:s.ytimg.c"
+"om/safebrowsing/rd/goog-malware-shavar_s_424\nu:s.ytimg.com/safebrowsing/rd/go"
+"og-malware-shavar_s_423\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_4"
+"22\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_420\nu:s.ytimg.com/saf"
+"ebrowsing/rd/goog-malware-shavar_s_419\nu:s.ytimg.com/safebrowsing/rd/goog-mal"
+"ware-shavar_s_414\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_409-411"
+"\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_405\nu:s.ytimg.com/safeb"
+"rowsing/rd/goog-malware-shavar_s_404\nu:s.ytimg.com/safebrowsing/rd/goog-malwa"
+"re-shavar_s_402\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_401\nu:s."
+"ytimg.com/safebrowsing/rd/goog-malware-shavar_a_973-978\nu:s.ytimg.com/safebro"
+"wsing/rd/goog-malware-shavar_a_937-972\nu:s.ytimg.com/safebrowsing/rd/goog-mal"
+"ware-shavar_a_931-936\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_a_925"
+"-930\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_a_919-924\ni:goog-phis"
+"h-shavar\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2633\nu:s.ytimg.co"
+"m/safebrowsing/rd/goog-phish-shavar_a_2632\nu:s.ytimg.com/safebrowsing/rd/goog"
+"-phish-shavar_a_2629-2631\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2"
+"626-2628\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2625\n";
+
+  std::string message_data(kMessage);
+
+  crypto::HMAC hmac(crypto::HMAC::SHA1);
+  ASSERT_TRUE(hmac.Init(kClientKey, kKeySize));
+  unsigned char calculated_hmac[kSHA1DigestSize];
+
+  EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize));
+  EXPECT_EQ(0, memcmp(kReceivedHmac, calculated_hmac, kSHA1DigestSize));
+}
+
+// Test cases from RFC 2202 section 3
+TEST(HMACTest, RFC2202TestCases) {
+  const struct {
+    const char *key;
+    const int key_len;
+    const char *data;
+    const int data_len;
+    const char *digest;
+  } cases[] = {
+    { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+          "\x0B\x0B\x0B\x0B", 20,
+      "Hi There", 8,
+      "\xB6\x17\x31\x86\x55\x05\x72\x64\xE2\x8B\xC0\xB6\xFB\x37\x8C\x8E"
+          "\xF1\x46\xBE\x00" },
+    { "Jefe", 4,
+      "what do ya want for nothing?", 28,
+      "\xEF\xFC\xDF\x6A\xE5\xEB\x2F\xA2\xD2\x74\x16\xD5\xF1\x84\xDF\x9C"
+          "\x25\x9A\x7C\x79" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA", 20,
+      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+          "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+          "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+          "\xDD\xDD", 50,
+      "\x12\x5D\x73\x42\xB9\xAC\x11\xCD\x91\xA3\x9A\xF4\x8A\xA1\x7B\x4F"
+          "\x63\xF1\x75\xD3" },
+    { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+          "\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
+      "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+          "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+          "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+          "\xCD\xCD", 50,
+      "\x4C\x90\x07\xF4\x02\x62\x50\xC6\xBC\x84\x14\xF9\xBF\x50\xC8\x6C"
+          "\x2D\x72\x35\xDA" },
+    { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+          "\x0C\x0C\x0C\x0C", 20,
+      "Test With Truncation", 20,
+      "\x4C\x1A\x03\x42\x4B\x55\xE0\x7F\xE7\xF2\x7B\xE1\xD5\x8B\xB9\x32"
+          "\x4A\x9A\x5A\x04" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+      80,
+      "Test Using Larger Than Block-Size Key - Hash Key First", 54,
+      "\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55"
+          "\xED\x40\x21\x12" },
+    { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+          "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+      80,
+      "Test Using Larger Than Block-Size Key and Larger "
+          "Than One Block-Size Data", 73,
+      "\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08"
+          "\xBB\xFF\x1A\x91" }
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    crypto::HMAC hmac(crypto::HMAC::SHA1);
+    ASSERT_TRUE(hmac.Init(reinterpret_cast<const unsigned char*>(cases[i].key),
+                          cases[i].key_len));
+    std::string data_string(cases[i].data, cases[i].data_len);
+    unsigned char digest[kSHA1DigestSize];
+    EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize));
+    EXPECT_EQ(0, memcmp(cases[i].digest, digest, kSHA1DigestSize));
+  }
+}
+
+// TODO(wtc): add other test vectors from RFC 4231.
+TEST(HMACTest, RFC4231TestCase6) {
+  unsigned char key[131];
+  for (size_t i = 0; i < sizeof(key); ++i)
+    key[i] = 0xaa;
+
+  std::string data = "Test Using Larger Than Block-Size Key - Hash Key First";
+  ASSERT_EQ(54U, data.size());
+
+  static unsigned char kKnownHMACSHA256[] = {
+    0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+    0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+    0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+    0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+  };
+
+  crypto::HMAC hmac(crypto::HMAC::SHA256);
+  ASSERT_TRUE(hmac.Init(key, sizeof(key)));
+  unsigned char calculated_hmac[kSHA256DigestSize];
+
+  EXPECT_EQ(kSHA256DigestSize, hmac.DigestLength());
+  EXPECT_TRUE(hmac.Sign(data, calculated_hmac, kSHA256DigestSize));
+  EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac, kSHA256DigestSize));
+}
+
+// Based on NSS's FIPS HMAC power-up self-test.
+TEST(HMACTest, NSSFIPSPowerUpSelfTest) {
+  static const char kKnownMessage[] =
+      "The test message for the MD2, MD5, and SHA-1 hashing algorithms.";
+
+  static const unsigned char kKnownSecretKey[] = {
+    0x46, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x20,
+    0x61, 0x6e, 0x64, 0x20, 0x54, 0x68, 0x75, 0x6e,
+    0x64, 0x65, 0x72, 0x42, 0x69, 0x72, 0x64, 0x20,
+    0x61, 0x72, 0x65, 0x20, 0x61, 0x77, 0x65, 0x73,
+    0x6f, 0x6d, 0x65, 0x21, 0x00
+  };
+
+  static const size_t kKnownSecretKeySize = sizeof(kKnownSecretKey);
+
+  // HMAC-SHA-1 known answer (20 bytes).
+  static const unsigned char kKnownHMACSHA1[] = {
+    0xd5, 0x85, 0xf6, 0x5b, 0x39, 0xfa, 0xb9, 0x05,
+    0x3b, 0x57, 0x1d, 0x61, 0xe7, 0xb8, 0x84, 0x1e,
+    0x5d, 0x0e, 0x1e, 0x11
+  };
+
+  // HMAC-SHA-256 known answer (32 bytes).
+  static const unsigned char kKnownHMACSHA256[] = {
+    0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44,
+    0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14, 0x22, 0xe0,
+    0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9,
+    0xa7, 0x1b, 0x56, 0x7d, 0x1d, 0x29, 0x40, 0x48
+  };
+
+  std::string message_data(kKnownMessage);
+
+  crypto::HMAC hmac(crypto::HMAC::SHA1);
+  ASSERT_TRUE(hmac.Init(kKnownSecretKey, kKnownSecretKeySize));
+  unsigned char calculated_hmac[kSHA1DigestSize];
+
+  EXPECT_EQ(kSHA1DigestSize, hmac.DigestLength());
+  EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize));
+  EXPECT_EQ(0, memcmp(kKnownHMACSHA1, calculated_hmac, kSHA1DigestSize));
+  EXPECT_TRUE(hmac.Verify(
+      message_data,
+      base::StringPiece(reinterpret_cast<const char*>(kKnownHMACSHA1),
+                        kSHA1DigestSize)));
+  EXPECT_TRUE(hmac.VerifyTruncated(
+      message_data,
+      base::StringPiece(reinterpret_cast<const char*>(kKnownHMACSHA1),
+                        kSHA1DigestSize / 2)));
+
+  crypto::HMAC hmac2(crypto::HMAC::SHA256);
+  ASSERT_TRUE(hmac2.Init(kKnownSecretKey, kKnownSecretKeySize));
+  unsigned char calculated_hmac2[kSHA256DigestSize];
+
+  EXPECT_TRUE(hmac2.Sign(message_data, calculated_hmac2, kSHA256DigestSize));
+  EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac2, kSHA256DigestSize));
+}
+
+TEST(HMACTest, HMACObjectReuse) {
+  crypto::HMAC hmac(crypto::HMAC::SHA1);
+  ASSERT_TRUE(
+      hmac.Init(reinterpret_cast<const unsigned char*>(kSimpleKey),
+                kSimpleKeyLength));
+  for (size_t i = 0; i < arraysize(kSimpleHmacCases); ++i) {
+    std::string data_string(kSimpleHmacCases[i].data,
+                            kSimpleHmacCases[i].data_len);
+    unsigned char digest[kSHA1DigestSize];
+    EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize));
+    EXPECT_EQ(0, memcmp(kSimpleHmacCases[i].digest, digest, kSHA1DigestSize));
+  }
+}
+
+TEST(HMACTest, Verify) {
+  crypto::HMAC hmac(crypto::HMAC::SHA1);
+  ASSERT_TRUE(
+      hmac.Init(reinterpret_cast<const unsigned char*>(kSimpleKey),
+                kSimpleKeyLength));
+  const char empty_digest[kSHA1DigestSize] = { 0 };
+  for (size_t i = 0; i < arraysize(kSimpleHmacCases); ++i) {
+    // Expected results
+    EXPECT_TRUE(hmac.Verify(
+        base::StringPiece(kSimpleHmacCases[i].data,
+                          kSimpleHmacCases[i].data_len),
+        base::StringPiece(kSimpleHmacCases[i].digest,
+                          kSHA1DigestSize)));
+    // Mismatched size
+    EXPECT_FALSE(hmac.Verify(
+        base::StringPiece(kSimpleHmacCases[i].data,
+                          kSimpleHmacCases[i].data_len),
+        base::StringPiece(kSimpleHmacCases[i].data,
+                          kSimpleHmacCases[i].data_len)));
+
+    // Expected size, mismatched data
+    EXPECT_FALSE(hmac.Verify(
+        base::StringPiece(kSimpleHmacCases[i].data,
+                          kSimpleHmacCases[i].data_len),
+        base::StringPiece(empty_digest, kSHA1DigestSize)));
+  }
+}
+
+TEST(HMACTest, EmptyKey) {
+  // Test vector from https://en.wikipedia.org/wiki/HMAC
+  const char* kExpectedDigest =
+      "\xFB\xDB\x1D\x1B\x18\xAA\x6C\x08\x32\x4B\x7D\x64\xB7\x1F\xB7\x63"
+      "\x70\x69\x0E\x1D";
+  base::StringPiece data("");
+
+  crypto::HMAC hmac(crypto::HMAC::SHA1);
+  ASSERT_TRUE(hmac.Init(nullptr, 0));
+
+  unsigned char digest[kSHA1DigestSize];
+  EXPECT_TRUE(hmac.Sign(data, digest, kSHA1DigestSize));
+  EXPECT_EQ(0, memcmp(kExpectedDigest, digest, kSHA1DigestSize));
+
+  EXPECT_TRUE(hmac.Verify(
+      data, base::StringPiece(kExpectedDigest, kSHA1DigestSize)));
+}
diff --git a/libchrome/crypto/nss_crypto_module_delegate.h b/libchrome/crypto/nss_crypto_module_delegate.h
new file mode 100644
index 0000000..6c1da68
--- /dev/null
+++ b/libchrome/crypto/nss_crypto_module_delegate.h
@@ -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.
+
+#ifndef CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_
+#define CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace crypto {
+
+// PK11_SetPasswordFunc is a global setting.  An implementation of
+// CryptoModuleBlockingPasswordDelegate should be passed using wincx() as the
+// user data argument (|wincx|) to relevant NSS functions, which the global
+// password handler will call to do the actual work. This delegate should only
+// be used in NSS calls on worker threads due to the blocking nature.
+class CryptoModuleBlockingPasswordDelegate {
+ public:
+  virtual ~CryptoModuleBlockingPasswordDelegate() {}
+
+  // Return a value suitable for passing to the |wincx| argument of relevant NSS
+  // functions. This should be used instead of passing the object pointer
+  // directly to avoid accidentally casting a pointer to a subclass to void* and
+  // then casting back to a pointer of the base class
+  void* wincx() { return this; }
+
+  // Requests a password to unlock |slot_name|. The interface is synchronous
+  // because NSS cannot issue an asynchronous request. |retry| is true if this
+  // is a request for the retry and we previously returned the wrong password.
+  // The implementation should set |*cancelled| to true if the user cancelled
+  // instead of entering a password, otherwise it should return the password the
+  // user entered.
+  virtual std::string RequestPassword(const std::string& slot_name, bool retry,
+                                      bool* cancelled) = 0;
+
+};
+
+// Extends CryptoModuleBlockingPasswordDelegate with the ability to return a
+// slot in which to act. (Eg, which slot to store a generated key in.)
+class NSSCryptoModuleDelegate : public CryptoModuleBlockingPasswordDelegate {
+ public:
+  ~NSSCryptoModuleDelegate() override {}
+
+  // Get the slot to store the generated key.
+  virtual ScopedPK11Slot RequestSlot() = 0;
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_NSS_CRYPTO_MODULE_DELEGATE_H_
diff --git a/libchrome/crypto/nss_key_util.cc b/libchrome/crypto/nss_key_util.cc
new file mode 100644
index 0000000..da8d9c3
--- /dev/null
+++ b/libchrome/crypto/nss_key_util.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 "crypto/nss_key_util.h"
+
+#include <cryptohi.h>
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <secmod.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+
+namespace crypto {
+
+namespace {
+
+struct PublicKeyInfoDeleter {
+  inline void operator()(CERTSubjectPublicKeyInfo* spki) {
+    SECKEY_DestroySubjectPublicKeyInfo(spki);
+  }
+};
+
+typedef std::unique_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
+    ScopedPublicKeyInfo;
+
+// Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing
+// the CKA_ID of that public key or nullptr on error.
+ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) {
+  // First, decode and save the public key.
+  SECItem key_der;
+  key_der.type = siBuffer;
+  key_der.data = const_cast<unsigned char*>(input.data());
+  key_der.len = input.size();
+
+  ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
+  if (!spki)
+    return nullptr;
+
+  ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get()));
+  if (!result)
+    return nullptr;
+
+  // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are
+  // supported.
+  if (SECKEY_GetPublicKeyType(result.get()) != rsaKey)
+    return nullptr;
+
+  return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
+}
+
+}  // namespace
+
+bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
+                           uint16_t num_bits,
+                           bool permanent,
+                           ScopedSECKEYPublicKey* public_key,
+                           ScopedSECKEYPrivateKey* private_key) {
+  DCHECK(slot);
+
+  PK11RSAGenParams param;
+  param.keySizeInBits = num_bits;
+  param.pe = 65537L;
+  SECKEYPublicKey* public_key_raw = nullptr;
+  private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
+                                          &param, &public_key_raw, permanent,
+                                          permanent /* sensitive */, nullptr));
+  if (!*private_key)
+    return false;
+
+  public_key->reset(public_key_raw);
+  return true;
+}
+
+ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
+    PK11SlotInfo* slot,
+    const std::vector<uint8_t>& input,
+    bool permanent) {
+  DCHECK(slot);
+
+  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+  DCHECK(arena);
+
+  // Excess data is illegal, but NSS silently accepts it, so first ensure that
+  // |input| consists of a single ASN.1 element.
+  SECItem input_item;
+  input_item.data = const_cast<unsigned char*>(input.data());
+  input_item.len = input.size();
+  SECItem der_private_key_info;
+  SECStatus rv =
+      SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
+                             SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
+  if (rv != SECSuccess)
+    return nullptr;
+
+  // Allow the private key to be used for key unwrapping, data decryption,
+  // and signature generation.
+  const unsigned int key_usage =
+      KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
+  SECKEYPrivateKey* key_raw = nullptr;
+  rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+      slot, &der_private_key_info, nullptr, nullptr, permanent,
+      permanent /* sensitive */, key_usage, &key_raw, nullptr);
+  if (rv != SECSuccess)
+    return nullptr;
+  return ScopedSECKEYPrivateKey(key_raw);
+}
+
+ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
+    const std::vector<uint8_t>& input) {
+  EnsureNSSInit();
+
+  ScopedSECItem cka_id(MakeIDFromSPKI(input));
+  if (!cka_id)
+    return nullptr;
+
+  // Search all slots in all modules for the key with the given ID.
+  AutoSECMODListReadLock auto_lock;
+  const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
+  for (const SECMODModuleList* item = head; item != nullptr;
+       item = item->next) {
+    int slot_count = item->module->loaded ? item->module->slotCount : 0;
+    for (int i = 0; i < slot_count; i++) {
+      // Look for the key in slot |i|.
+      ScopedSECKEYPrivateKey key(
+          PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
+      if (key)
+        return key;
+    }
+  }
+
+  // The key wasn't found in any module.
+  return nullptr;
+}
+
+ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
+    const std::vector<uint8_t>& input,
+    PK11SlotInfo* slot) {
+  DCHECK(slot);
+
+  ScopedSECItem cka_id(MakeIDFromSPKI(input));
+  if (!cka_id)
+    return nullptr;
+
+  return ScopedSECKEYPrivateKey(
+      PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/nss_key_util.h b/libchrome/crypto/nss_key_util.h
new file mode 100644
index 0000000..86934dd
--- /dev/null
+++ b/libchrome/crypto/nss_key_util.h
@@ -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.
+
+#ifndef CRYPTO_NSS_KEY_UTIL_H_
+#define CRYPTO_NSS_KEY_UTIL_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+#include "crypto/scoped_nss_types.h"
+
+typedef struct PK11SlotInfoStr PK11SlotInfo;
+
+namespace crypto {
+
+// Generates a new RSA keypair of size |num_bits| in |slot|. Returns true on
+// success and false on failure. If |permanent| is true, the resulting key is
+// permanent and is not exportable in plaintext form.
+CRYPTO_EXPORT bool GenerateRSAKeyPairNSS(
+    PK11SlotInfo* slot,
+    uint16_t num_bits,
+    bool permanent,
+    ScopedSECKEYPublicKey* out_public_key,
+    ScopedSECKEYPrivateKey* out_private_key);
+
+// Imports a private key from |input| into |slot|. |input| is interpreted as a
+// DER-encoded PrivateKeyInfo block from PKCS #8. Returns nullptr on error. If
+// |permanent| is true, the resulting key is permanent and is not exportable in
+// plaintext form.
+CRYPTO_EXPORT ScopedSECKEYPrivateKey
+ImportNSSKeyFromPrivateKeyInfo(PK11SlotInfo* slot,
+                               const std::vector<uint8_t>& input,
+                               bool permanent);
+
+// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for
+// the private key half in the key database. Returns the private key on success
+// or nullptr on error.
+CRYPTO_EXPORT ScopedSECKEYPrivateKey
+FindNSSKeyFromPublicKeyInfo(const std::vector<uint8_t>& input);
+
+// Decodes |input| as a DER-encoded X.509 SubjectPublicKeyInfo and searches for
+// the private key half in the slot specified by |slot|. Returns the private key
+// on success or nullptr on error.
+CRYPTO_EXPORT ScopedSECKEYPrivateKey
+FindNSSKeyFromPublicKeyInfoInSlot(const std::vector<uint8_t>& input,
+                                  PK11SlotInfo* slot);
+
+}  // namespace crypto
+
+#endif  // CRYPTO_NSS_KEY_UTIL_H_
diff --git a/libchrome/crypto/nss_key_util_unittest.cc b/libchrome/crypto/nss_key_util_unittest.cc
new file mode 100644
index 0000000..ced9850
--- /dev/null
+++ b/libchrome/crypto/nss_key_util_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 "crypto/nss_key_util.h"
+
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+class NSSKeyUtilTest : public testing::Test {
+ public:
+  void SetUp() override {
+    EnsureNSSInit();
+
+    internal_slot_.reset(PK11_GetInternalSlot());
+    ASSERT_TRUE(internal_slot_);
+  }
+
+  PK11SlotInfo* internal_slot() { return internal_slot_.get(); }
+
+ private:
+  ScopedPK11Slot internal_slot_;
+};
+
+TEST_F(NSSKeyUtilTest, GenerateRSAKeyPairNSS) {
+  const int kKeySizeBits = 1024;
+
+  ScopedSECKEYPublicKey public_key;
+  ScopedSECKEYPrivateKey private_key;
+  ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), kKeySizeBits,
+                                    false /* not permanent */, &public_key,
+                                    &private_key));
+
+  EXPECT_EQ(rsaKey, SECKEY_GetPublicKeyType(public_key.get()));
+  EXPECT_EQ(rsaKey, SECKEY_GetPrivateKeyType(private_key.get()));
+  EXPECT_EQ((kKeySizeBits + 7) / 8,
+            PK11_GetPrivateModulusLen(private_key.get()));
+}
+
+TEST_F(NSSKeyUtilTest, FindNSSKeyFromPublicKeyInfo) {
+  // Create an NSS keypair, which will put the keys in the user's NSSDB.
+  ScopedSECKEYPublicKey public_key;
+  ScopedSECKEYPrivateKey private_key;
+  ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512,
+                                    false /* not permanent */, &public_key,
+                                    &private_key));
+
+  ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get()));
+  ASSERT_TRUE(item);
+  std::vector<uint8_t> public_key_der(item->data, item->data + item->len);
+
+  ScopedSECKEYPrivateKey private_key2 =
+      FindNSSKeyFromPublicKeyInfo(public_key_der);
+  ASSERT_TRUE(private_key2);
+  EXPECT_EQ(private_key->pkcs11ID, private_key2->pkcs11ID);
+}
+
+TEST_F(NSSKeyUtilTest, FailedFindNSSKeyFromPublicKeyInfo) {
+  // Create an NSS keypair, which will put the keys in the user's NSSDB.
+  ScopedSECKEYPublicKey public_key;
+  ScopedSECKEYPrivateKey private_key;
+  ASSERT_TRUE(GenerateRSAKeyPairNSS(internal_slot(), 512,
+                                    false /* not permanent */, &public_key,
+                                    &private_key));
+
+  ScopedSECItem item(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get()));
+  ASSERT_TRUE(item);
+  std::vector<uint8_t> public_key_der(item->data, item->data + item->len);
+
+  // Remove the keys from the DB, and make sure we can't find them again.
+  PK11_DestroyTokenObject(private_key->pkcs11Slot, private_key->pkcs11ID);
+  PK11_DestroyTokenObject(public_key->pkcs11Slot, public_key->pkcs11ID);
+
+  EXPECT_FALSE(FindNSSKeyFromPublicKeyInfo(public_key_der));
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/nss_util.cc b/libchrome/crypto/nss_util.cc
new file mode 100644
index 0000000..96ee060
--- /dev/null
+++ b/libchrome/crypto/nss_util.cc
@@ -0,0 +1,1034 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/nss_util.h"
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <plarena.h>
+#include <prerror.h>
+#include <prinit.h>
+#include <prtime.h>
+#include <secmod.h>
+
+#include <memory>
+#include <utility>
+
+#include "crypto/nss_util_internal.h"
+
+#if defined(OS_OPENBSD)
+#include <sys/mount.h>
+#include <sys/param.h>
+#endif
+
+#if defined(OS_CHROMEOS)
+#include <dlfcn.h>
+#endif
+
+#include <map>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/cpu.h"
+#include "base/debug/alias.h"
+#include "base/debug/stack_trace.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/native_library.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/threading/worker_pool.h"
+#include "build/build_config.h"
+
+#if !defined(OS_CHROMEOS)
+#include "base/base_paths.h"
+#include "base/path_service.h"
+#endif
+
+// USE_NSS_CERTS means NSS is used for certificates and platform integration.
+// This requires additional support to manage the platform certificate and key
+// stores.
+#if defined(USE_NSS_CERTS)
+#include "base/synchronization/lock.h"
+#include "crypto/nss_crypto_module_delegate.h"
+#endif  // defined(USE_NSS_CERTS)
+
+namespace crypto {
+
+namespace {
+
+#if defined(OS_CHROMEOS)
+const char kUserNSSDatabaseName[] = "UserNSSDB";
+
+// Constants for loading the Chrome OS TPM-backed PKCS #11 library.
+const char kChapsModuleName[] = "Chaps";
+const char kChapsPath[] = "libchaps.so";
+
+// Fake certificate authority database used for testing.
+static const base::FilePath::CharType kReadOnlyCertDB[] =
+    FILE_PATH_LITERAL("/etc/fake_root_ca/nssdb");
+#endif  // defined(OS_CHROMEOS)
+
+std::string GetNSSErrorMessage() {
+  std::string result;
+  if (PR_GetErrorTextLength()) {
+    std::unique_ptr<char[]> error_text(new char[PR_GetErrorTextLength() + 1]);
+    PRInt32 copied = PR_GetErrorText(error_text.get());
+    result = std::string(error_text.get(), copied);
+  } else {
+    result = base::StringPrintf("NSS error code: %d", PR_GetError());
+  }
+  return result;
+}
+
+#if defined(USE_NSS_CERTS)
+#if !defined(OS_CHROMEOS)
+base::FilePath GetDefaultConfigDirectory() {
+  base::FilePath dir;
+  PathService::Get(base::DIR_HOME, &dir);
+  if (dir.empty()) {
+    LOG(ERROR) << "Failed to get home directory.";
+    return dir;
+  }
+  dir = dir.AppendASCII(".pki").AppendASCII("nssdb");
+  if (!base::CreateDirectory(dir)) {
+    LOG(ERROR) << "Failed to create " << dir.value() << " directory.";
+    dir.clear();
+  }
+  DVLOG(2) << "DefaultConfigDirectory: " << dir.value();
+  return dir;
+}
+#endif  // !defined(IS_CHROMEOS)
+
+// On non-Chrome OS platforms, return the default config directory. On Chrome OS
+// test images, return a read-only directory with fake root CA certs (which are
+// used by the local Google Accounts server mock we use when testing our login
+// code). On Chrome OS non-test images (where the read-only directory doesn't
+// exist), return an empty path.
+base::FilePath GetInitialConfigDirectory() {
+#if defined(OS_CHROMEOS)
+  base::FilePath database_dir = base::FilePath(kReadOnlyCertDB);
+  if (!base::PathExists(database_dir))
+    database_dir.clear();
+  return database_dir;
+#else
+  return GetDefaultConfigDirectory();
+#endif  // defined(OS_CHROMEOS)
+}
+
+// This callback for NSS forwards all requests to a caller-specified
+// CryptoModuleBlockingPasswordDelegate object.
+char* PKCS11PasswordFunc(PK11SlotInfo* slot, PRBool retry, void* arg) {
+  crypto::CryptoModuleBlockingPasswordDelegate* delegate =
+      reinterpret_cast<crypto::CryptoModuleBlockingPasswordDelegate*>(arg);
+  if (delegate) {
+    bool cancelled = false;
+    std::string password = delegate->RequestPassword(PK11_GetTokenName(slot),
+                                                     retry != PR_FALSE,
+                                                     &cancelled);
+    if (cancelled)
+      return NULL;
+    char* result = PORT_Strdup(password.c_str());
+    password.replace(0, password.size(), password.size(), 0);
+    return result;
+  }
+  DLOG(ERROR) << "PK11 password requested with NULL arg";
+  return NULL;
+}
+
+// NSS creates a local cache of the sqlite database if it detects that the
+// filesystem the database is on is much slower than the local disk.  The
+// detection doesn't work with the latest versions of sqlite, such as 3.6.22
+// (NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=578561).  So we set
+// the NSS environment variable NSS_SDB_USE_CACHE to "yes" to override NSS's
+// detection when database_dir is on NFS.  See http://crbug.com/48585.
+//
+// TODO(wtc): port this function to other USE_NSS_CERTS platforms.  It is
+// defined only for OS_LINUX and OS_OPENBSD simply because the statfs structure
+// is OS-specific.
+//
+// Because this function sets an environment variable it must be run before we
+// go multi-threaded.
+void UseLocalCacheOfNSSDatabaseIfNFS(const base::FilePath& database_dir) {
+  bool db_on_nfs = false;
+#if defined(OS_LINUX)
+  base::FileSystemType fs_type = base::FILE_SYSTEM_UNKNOWN;
+  if (base::GetFileSystemType(database_dir, &fs_type))
+    db_on_nfs = (fs_type == base::FILE_SYSTEM_NFS);
+#elif defined(OS_OPENBSD)
+  struct statfs buf;
+  if (statfs(database_dir.value().c_str(), &buf) == 0)
+    db_on_nfs = (strcmp(buf.f_fstypename, MOUNT_NFS) == 0);
+#else
+  NOTIMPLEMENTED();
+#endif
+
+  if (db_on_nfs) {
+    std::unique_ptr<base::Environment> env(base::Environment::Create());
+    static const char kUseCacheEnvVar[] = "NSS_SDB_USE_CACHE";
+    if (!env->HasVar(kUseCacheEnvVar))
+      env->SetVar(kUseCacheEnvVar, "yes");
+  }
+}
+
+#endif  // defined(USE_NSS_CERTS)
+
+// A singleton to initialize/deinitialize NSPR.
+// Separate from the NSS singleton because we initialize NSPR on the UI thread.
+// Now that we're leaking the singleton, we could merge back with the NSS
+// singleton.
+class NSPRInitSingleton {
+ private:
+  friend struct base::DefaultLazyInstanceTraits<NSPRInitSingleton>;
+
+  NSPRInitSingleton() {
+    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+  }
+
+  // NOTE(willchan): We don't actually execute this code since we leak NSS to
+  // prevent non-joinable threads from using NSS after it's already been shut
+  // down.
+  ~NSPRInitSingleton() {
+    PL_ArenaFinish();
+    PRStatus prstatus = PR_Cleanup();
+    if (prstatus != PR_SUCCESS)
+      LOG(ERROR) << "PR_Cleanup failed; was NSPR initialized on wrong thread?";
+  }
+};
+
+base::LazyInstance<NSPRInitSingleton>::Leaky
+    g_nspr_singleton = LAZY_INSTANCE_INITIALIZER;
+
+// Force a crash with error info on NSS_NoDB_Init failure.
+void CrashOnNSSInitFailure() {
+  int nss_error = PR_GetError();
+  int os_error = PR_GetOSError();
+  base::debug::Alias(&nss_error);
+  base::debug::Alias(&os_error);
+  LOG(ERROR) << "Error initializing NSS without a persistent database: "
+             << GetNSSErrorMessage();
+  LOG(FATAL) << "nss_error=" << nss_error << ", os_error=" << os_error;
+}
+
+#if defined(OS_CHROMEOS)
+class ChromeOSUserData {
+ public:
+  explicit ChromeOSUserData(ScopedPK11Slot public_slot)
+      : public_slot_(std::move(public_slot)),
+        private_slot_initialization_started_(false) {}
+  ~ChromeOSUserData() {
+    if (public_slot_) {
+      SECStatus status = SECMOD_CloseUserDB(public_slot_.get());
+      if (status != SECSuccess)
+        PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
+    }
+  }
+
+  ScopedPK11Slot GetPublicSlot() {
+    return ScopedPK11Slot(
+        public_slot_ ? PK11_ReferenceSlot(public_slot_.get()) : NULL);
+  }
+
+  ScopedPK11Slot GetPrivateSlot(
+      const base::Callback<void(ScopedPK11Slot)>& callback) {
+    if (private_slot_)
+      return ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get()));
+    if (!callback.is_null())
+      tpm_ready_callback_list_.push_back(callback);
+    return ScopedPK11Slot();
+  }
+
+  void SetPrivateSlot(ScopedPK11Slot private_slot) {
+    DCHECK(!private_slot_);
+    private_slot_ = std::move(private_slot);
+
+    SlotReadyCallbackList callback_list;
+    callback_list.swap(tpm_ready_callback_list_);
+    for (SlotReadyCallbackList::iterator i = callback_list.begin();
+         i != callback_list.end();
+         ++i) {
+      (*i).Run(ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())));
+    }
+  }
+
+  bool private_slot_initialization_started() const {
+      return private_slot_initialization_started_;
+  }
+
+  void set_private_slot_initialization_started() {
+      private_slot_initialization_started_ = true;
+  }
+
+ private:
+  ScopedPK11Slot public_slot_;
+  ScopedPK11Slot private_slot_;
+
+  bool private_slot_initialization_started_;
+
+  typedef std::vector<base::Callback<void(ScopedPK11Slot)> >
+      SlotReadyCallbackList;
+  SlotReadyCallbackList tpm_ready_callback_list_;
+};
+
+class ScopedChapsLoadFixup {
+  public:
+    ScopedChapsLoadFixup();
+    ~ScopedChapsLoadFixup();
+
+  private:
+#if defined(COMPONENT_BUILD)
+    void *chaps_handle_;
+#endif
+};
+
+#if defined(COMPONENT_BUILD)
+
+ScopedChapsLoadFixup::ScopedChapsLoadFixup() {
+  // HACK: libchaps links the system protobuf and there are symbol conflicts
+  // with the bundled copy. Load chaps with RTLD_DEEPBIND to workaround.
+  chaps_handle_ = dlopen(kChapsPath, RTLD_LOCAL | RTLD_NOW | RTLD_DEEPBIND);
+}
+
+ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {
+  // LoadModule() will have taken a 2nd reference.
+  if (chaps_handle_)
+    dlclose(chaps_handle_);
+}
+
+#else
+
+ScopedChapsLoadFixup::ScopedChapsLoadFixup() {}
+ScopedChapsLoadFixup::~ScopedChapsLoadFixup() {}
+
+#endif  // defined(COMPONENT_BUILD)
+#endif  // defined(OS_CHROMEOS)
+
+class NSSInitSingleton {
+ public:
+#if defined(OS_CHROMEOS)
+  // Used with PostTaskAndReply to pass handles to worker thread and back.
+  struct TPMModuleAndSlot {
+    explicit TPMModuleAndSlot(SECMODModule* init_chaps_module)
+        : chaps_module(init_chaps_module) {}
+    SECMODModule* chaps_module;
+    crypto::ScopedPK11Slot tpm_slot;
+  };
+
+  ScopedPK11Slot OpenPersistentNSSDBForPath(const std::string& db_name,
+                                            const base::FilePath& path) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    // NSS is allowed to do IO on the current thread since dispatching
+    // to a dedicated thread would still have the affect of blocking
+    // the current thread, due to NSS's internal locking requirements
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+    base::FilePath nssdb_path = path.AppendASCII(".pki").AppendASCII("nssdb");
+    if (!base::CreateDirectory(nssdb_path)) {
+      LOG(ERROR) << "Failed to create " << nssdb_path.value() << " directory.";
+      return ScopedPK11Slot();
+    }
+    return OpenSoftwareNSSDB(nssdb_path, db_name);
+  }
+
+  void EnableTPMTokenForNSS() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+
+    // If this gets set, then we'll use the TPM for certs with
+    // private keys, otherwise we'll fall back to the software
+    // implementation.
+    tpm_token_enabled_for_nss_ = true;
+  }
+
+  bool IsTPMTokenEnabledForNSS() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    return tpm_token_enabled_for_nss_;
+  }
+
+  void InitializeTPMTokenAndSystemSlot(
+      int system_slot_id,
+      const base::Callback<void(bool)>& callback) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    // Should not be called while there is already an initialization in
+    // progress.
+    DCHECK(!initializing_tpm_token_);
+    // If EnableTPMTokenForNSS hasn't been called, return false.
+    if (!tpm_token_enabled_for_nss_) {
+      base::MessageLoop::current()->PostTask(FROM_HERE,
+                                             base::Bind(callback, false));
+      return;
+    }
+
+    // If everything is already initialized, then return true.
+    // Note that only |tpm_slot_| is checked, since |chaps_module_| could be
+    // NULL in tests while |tpm_slot_| has been set to the test DB.
+    if (tpm_slot_) {
+      base::MessageLoop::current()->PostTask(FROM_HERE,
+                                             base::Bind(callback, true));
+      return;
+    }
+
+    // Note that a reference is not taken to chaps_module_. This is safe since
+    // NSSInitSingleton is Leaky, so the reference it holds is never released.
+    std::unique_ptr<TPMModuleAndSlot> tpm_args(
+        new TPMModuleAndSlot(chaps_module_));
+    TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
+    if (base::WorkerPool::PostTaskAndReply(
+            FROM_HERE,
+            base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
+                       system_slot_id,
+                       tpm_args_ptr),
+            base::Bind(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
+                       base::Unretained(this),  // NSSInitSingleton is leaky
+                       callback,
+                       base::Passed(&tpm_args)),
+            true /* task_is_slow */
+            )) {
+      initializing_tpm_token_ = true;
+    } else {
+      base::MessageLoop::current()->PostTask(FROM_HERE,
+                                             base::Bind(callback, false));
+    }
+  }
+
+  static void InitializeTPMTokenOnWorkerThread(CK_SLOT_ID token_slot_id,
+                                               TPMModuleAndSlot* tpm_args) {
+    // This tries to load the Chaps module so NSS can talk to the hardware
+    // TPM.
+    if (!tpm_args->chaps_module) {
+      ScopedChapsLoadFixup chaps_loader;
+
+      DVLOG(3) << "Loading chaps...";
+      tpm_args->chaps_module = LoadModule(
+          kChapsModuleName,
+          kChapsPath,
+          // For more details on these parameters, see:
+          // https://developer.mozilla.org/en/PKCS11_Module_Specs
+          // slotFlags=[PublicCerts] -- Certificates and public keys can be
+          //   read from this slot without requiring a call to C_Login.
+          // askpw=only -- Only authenticate to the token when necessary.
+          "NSS=\"slotParams=(0={slotFlags=[PublicCerts] askpw=only})\"");
+    }
+    if (tpm_args->chaps_module) {
+      tpm_args->tpm_slot =
+          GetTPMSlotForIdOnWorkerThread(tpm_args->chaps_module, token_slot_id);
+    }
+  }
+
+  void OnInitializedTPMTokenAndSystemSlot(
+      const base::Callback<void(bool)>& callback,
+      std::unique_ptr<TPMModuleAndSlot> tpm_args) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DVLOG(2) << "Loaded chaps: " << !!tpm_args->chaps_module
+             << ", got tpm slot: " << !!tpm_args->tpm_slot;
+
+    chaps_module_ = tpm_args->chaps_module;
+    tpm_slot_ = std::move(tpm_args->tpm_slot);
+    if (!chaps_module_ && test_system_slot_) {
+      // chromeos_unittests try to test the TPM initialization process. If we
+      // have a test DB open, pretend that it is the TPM slot.
+      tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
+    }
+    initializing_tpm_token_ = false;
+
+    if (tpm_slot_)
+      RunAndClearTPMReadyCallbackList();
+
+    callback.Run(!!tpm_slot_);
+  }
+
+  void RunAndClearTPMReadyCallbackList() {
+    TPMReadyCallbackList callback_list;
+    callback_list.swap(tpm_ready_callback_list_);
+    for (TPMReadyCallbackList::iterator i = callback_list.begin();
+         i != callback_list.end();
+         ++i) {
+      i->Run();
+    }
+  }
+
+  bool IsTPMTokenReady(const base::Closure& callback) {
+    if (!callback.is_null()) {
+      // Cannot DCHECK in the general case yet, but since the callback is
+      // a new addition to the API, DCHECK to make sure at least the new uses
+      // don't regress.
+      DCHECK(thread_checker_.CalledOnValidThread());
+    } else if (!thread_checker_.CalledOnValidThread()) {
+      // TODO(mattm): Change to DCHECK when callers have been fixed.
+      DVLOG(1) << "Called on wrong thread.\n"
+               << base::debug::StackTrace().ToString();
+    }
+
+    if (tpm_slot_)
+      return true;
+
+    if (!callback.is_null())
+      tpm_ready_callback_list_.push_back(callback);
+
+    return false;
+  }
+
+  // Note that CK_SLOT_ID is an unsigned long, but cryptohome gives us the slot
+  // id as an int. This should be safe since this is only used with chaps, which
+  // we also control.
+  static crypto::ScopedPK11Slot GetTPMSlotForIdOnWorkerThread(
+      SECMODModule* chaps_module,
+      CK_SLOT_ID slot_id) {
+    DCHECK(chaps_module);
+
+    DVLOG(3) << "Poking chaps module.";
+    SECStatus rv = SECMOD_UpdateSlotList(chaps_module);
+    if (rv != SECSuccess)
+      PLOG(ERROR) << "SECMOD_UpdateSlotList failed: " << PORT_GetError();
+
+    PK11SlotInfo* slot = SECMOD_LookupSlot(chaps_module->moduleID, slot_id);
+    if (!slot)
+      LOG(ERROR) << "TPM slot " << slot_id << " not found.";
+    return crypto::ScopedPK11Slot(slot);
+  }
+
+  bool InitializeNSSForChromeOSUser(const std::string& username_hash,
+                                    const base::FilePath& path) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    if (chromeos_user_map_.find(username_hash) != chromeos_user_map_.end()) {
+      // This user already exists in our mapping.
+      DVLOG(2) << username_hash << " already initialized.";
+      return false;
+    }
+
+    DVLOG(2) << "Opening NSS DB " << path.value();
+    std::string db_name = base::StringPrintf(
+        "%s %s", kUserNSSDatabaseName, username_hash.c_str());
+    ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
+    chromeos_user_map_[username_hash] =
+        new ChromeOSUserData(std::move(public_slot));
+    return true;
+  }
+
+  bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+
+    return !chromeos_user_map_[username_hash]
+                ->private_slot_initialization_started();
+  }
+
+  void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+
+    chromeos_user_map_[username_hash]
+        ->set_private_slot_initialization_started();
+  }
+
+  void InitializeTPMForChromeOSUser(const std::string& username_hash,
+                                    CK_SLOT_ID slot_id) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+    DCHECK(chromeos_user_map_[username_hash]->
+               private_slot_initialization_started());
+
+    if (!chaps_module_)
+      return;
+
+    // Note that a reference is not taken to chaps_module_. This is safe since
+    // NSSInitSingleton is Leaky, so the reference it holds is never released.
+    std::unique_ptr<TPMModuleAndSlot> tpm_args(
+        new TPMModuleAndSlot(chaps_module_));
+    TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
+    base::WorkerPool::PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
+                   slot_id,
+                   tpm_args_ptr),
+        base::Bind(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
+                   base::Unretained(this),  // NSSInitSingleton is leaky
+                   username_hash,
+                   base::Passed(&tpm_args)),
+        true /* task_is_slow */
+        );
+  }
+
+  void OnInitializedTPMForChromeOSUser(
+      const std::string& username_hash,
+      std::unique_ptr<TPMModuleAndSlot> tpm_args) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DVLOG(2) << "Got tpm slot for " << username_hash << " "
+             << !!tpm_args->tpm_slot;
+    chromeos_user_map_[username_hash]->SetPrivateSlot(
+        std::move(tpm_args->tpm_slot));
+  }
+
+  void InitializePrivateSoftwareSlotForChromeOSUser(
+      const std::string& username_hash) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    VLOG(1) << "using software private slot for " << username_hash;
+    DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+    DCHECK(chromeos_user_map_[username_hash]->
+               private_slot_initialization_started());
+
+    chromeos_user_map_[username_hash]->SetPrivateSlot(
+        chromeos_user_map_[username_hash]->GetPublicSlot());
+  }
+
+  ScopedPK11Slot GetPublicSlotForChromeOSUser(
+      const std::string& username_hash) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+
+    if (username_hash.empty()) {
+      DVLOG(2) << "empty username_hash";
+      return ScopedPK11Slot();
+    }
+
+    if (chromeos_user_map_.find(username_hash) == chromeos_user_map_.end()) {
+      LOG(ERROR) << username_hash << " not initialized.";
+      return ScopedPK11Slot();
+    }
+    return chromeos_user_map_[username_hash]->GetPublicSlot();
+  }
+
+  ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+      const std::string& username_hash,
+      const base::Callback<void(ScopedPK11Slot)>& callback) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+
+    if (username_hash.empty()) {
+      DVLOG(2) << "empty username_hash";
+      if (!callback.is_null()) {
+        base::MessageLoop::current()->PostTask(
+            FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot())));
+      }
+      return ScopedPK11Slot();
+    }
+
+    DCHECK(chromeos_user_map_.find(username_hash) != chromeos_user_map_.end());
+
+    return chromeos_user_map_[username_hash]->GetPrivateSlot(callback);
+  }
+
+  void CloseChromeOSUserForTesting(const std::string& username_hash) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    ChromeOSUserMap::iterator i = chromeos_user_map_.find(username_hash);
+    DCHECK(i != chromeos_user_map_.end());
+    delete i->second;
+    chromeos_user_map_.erase(i);
+  }
+
+  void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
+    // Ensure that a previous value of test_system_slot_ is not overwritten.
+    // Unsetting, i.e. setting a NULL, however is allowed.
+    DCHECK(!slot || !test_system_slot_);
+    test_system_slot_ = std::move(slot);
+    if (test_system_slot_) {
+      tpm_slot_.reset(PK11_ReferenceSlot(test_system_slot_.get()));
+      RunAndClearTPMReadyCallbackList();
+    } else {
+      tpm_slot_.reset();
+    }
+  }
+#endif  // defined(OS_CHROMEOS)
+
+#if !defined(OS_CHROMEOS)
+  PK11SlotInfo* GetPersistentNSSKeySlot() {
+    // TODO(mattm): Change to DCHECK when callers have been fixed.
+    if (!thread_checker_.CalledOnValidThread()) {
+      DVLOG(1) << "Called on wrong thread.\n"
+               << base::debug::StackTrace().ToString();
+    }
+
+    return PK11_GetInternalKeySlot();
+  }
+#endif
+
+#if defined(OS_CHROMEOS)
+  void GetSystemNSSKeySlotCallback(
+      const base::Callback<void(ScopedPK11Slot)>& callback) {
+    callback.Run(ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get())));
+  }
+
+  ScopedPK11Slot GetSystemNSSKeySlot(
+      const base::Callback<void(ScopedPK11Slot)>& callback) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    // TODO(mattm): chromeos::TPMTokenloader always calls
+    // InitializeTPMTokenAndSystemSlot with slot 0.  If the system slot is
+    // disabled, tpm_slot_ will be the first user's slot instead. Can that be
+    // detected and return NULL instead?
+
+    base::Closure wrapped_callback;
+    if (!callback.is_null()) {
+      wrapped_callback =
+          base::Bind(&NSSInitSingleton::GetSystemNSSKeySlotCallback,
+                     base::Unretained(this) /* singleton is leaky */,
+                     callback);
+    }
+    if (IsTPMTokenReady(wrapped_callback))
+      return ScopedPK11Slot(PK11_ReferenceSlot(tpm_slot_.get()));
+    return ScopedPK11Slot();
+  }
+#endif
+
+#if defined(USE_NSS_CERTS)
+  base::Lock* write_lock() {
+    return &write_lock_;
+  }
+#endif  // defined(USE_NSS_CERTS)
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<NSSInitSingleton>;
+
+  NSSInitSingleton()
+      : tpm_token_enabled_for_nss_(false),
+        initializing_tpm_token_(false),
+        chaps_module_(NULL),
+        root_(NULL) {
+    // It's safe to construct on any thread, since LazyInstance will prevent any
+    // other threads from accessing until the constructor is done.
+    thread_checker_.DetachFromThread();
+
+    EnsureNSPRInit();
+
+    // We *must* have NSS >= 3.14.3.
+    static_assert(
+        (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) ||
+        (NSS_VMAJOR == 3 && NSS_VMINOR > 14) ||
+        (NSS_VMAJOR > 3),
+        "nss version check failed");
+    // Also check the run-time NSS version.
+    // NSS_VersionCheck is a >= check, not strict equality.
+    if (!NSS_VersionCheck("3.14.3")) {
+      LOG(FATAL) << "NSS_VersionCheck(\"3.14.3\") failed. NSS >= 3.14.3 is "
+                    "required. Please upgrade to the latest NSS, and if you "
+                    "still get this error, contact your distribution "
+                    "maintainer.";
+    }
+
+    SECStatus status = SECFailure;
+    bool nodb_init = false;
+
+#if !defined(USE_NSS_CERTS)
+    // Use the system certificate store, so initialize NSS without database.
+    nodb_init = true;
+#endif
+
+    if (nodb_init) {
+      status = NSS_NoDB_Init(NULL);
+      if (status != SECSuccess) {
+        CrashOnNSSInitFailure();
+        return;
+      }
+#if defined(OS_IOS)
+      root_ = InitDefaultRootCerts();
+#endif  // defined(OS_IOS)
+    } else {
+#if defined(USE_NSS_CERTS)
+      base::FilePath database_dir = GetInitialConfigDirectory();
+      if (!database_dir.empty()) {
+        // This duplicates the work which should have been done in
+        // EarlySetupForNSSInit. However, this function is idempotent so
+        // there's no harm done.
+        UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
+
+        // Initialize with a persistent database (likely, ~/.pki/nssdb).
+        // Use "sql:" which can be shared by multiple processes safely.
+        std::string nss_config_dir =
+            base::StringPrintf("sql:%s", database_dir.value().c_str());
+#if defined(OS_CHROMEOS)
+        status = NSS_Init(nss_config_dir.c_str());
+#else
+        status = NSS_InitReadWrite(nss_config_dir.c_str());
+#endif
+        if (status != SECSuccess) {
+          LOG(ERROR) << "Error initializing NSS with a persistent "
+                        "database (" << nss_config_dir
+                     << "): " << GetNSSErrorMessage();
+        }
+      }
+      if (status != SECSuccess) {
+        VLOG(1) << "Initializing NSS without a persistent database.";
+        status = NSS_NoDB_Init(NULL);
+        if (status != SECSuccess) {
+          CrashOnNSSInitFailure();
+          return;
+        }
+      }
+
+      PK11_SetPasswordFunc(PKCS11PasswordFunc);
+
+      // If we haven't initialized the password for the NSS databases,
+      // initialize an empty-string password so that we don't need to
+      // log in.
+      PK11SlotInfo* slot = PK11_GetInternalKeySlot();
+      if (slot) {
+        // PK11_InitPin may write to the keyDB, but no other thread can use NSS
+        // yet, so we don't need to lock.
+        if (PK11_NeedUserInit(slot))
+          PK11_InitPin(slot, NULL, NULL);
+        PK11_FreeSlot(slot);
+      }
+
+      root_ = InitDefaultRootCerts();
+#endif  // defined(USE_NSS_CERTS)
+    }
+
+    // Disable MD5 certificate signatures. (They are disabled by default in
+    // NSS 3.14.)
+    NSS_SetAlgorithmPolicy(SEC_OID_MD5, 0, NSS_USE_ALG_IN_CERT_SIGNATURE);
+    NSS_SetAlgorithmPolicy(SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
+                           0, NSS_USE_ALG_IN_CERT_SIGNATURE);
+  }
+
+  // NOTE(willchan): We don't actually execute this code since we leak NSS to
+  // prevent non-joinable threads from using NSS after it's already been shut
+  // down.
+  ~NSSInitSingleton() {
+#if defined(OS_CHROMEOS)
+    STLDeleteValues(&chromeos_user_map_);
+#endif
+    tpm_slot_.reset();
+    if (root_) {
+      SECMOD_UnloadUserModule(root_);
+      SECMOD_DestroyModule(root_);
+      root_ = NULL;
+    }
+    if (chaps_module_) {
+      SECMOD_UnloadUserModule(chaps_module_);
+      SECMOD_DestroyModule(chaps_module_);
+      chaps_module_ = NULL;
+    }
+
+    SECStatus status = NSS_Shutdown();
+    if (status != SECSuccess) {
+      // We VLOG(1) because this failure is relatively harmless (leaking, but
+      // we're shutting down anyway).
+      VLOG(1) << "NSS_Shutdown failed; see http://crbug.com/4609";
+    }
+  }
+
+  // Load nss's built-in root certs.
+  SECMODModule* InitDefaultRootCerts() {
+    SECMODModule* root = LoadModule("Root Certs", "libnssckbi.so", NULL);
+    if (root)
+      return root;
+
+    // Aw, snap.  Can't find/load root cert shared library.
+    // This will make it hard to talk to anybody via https.
+    // TODO(mattm): Re-add the NOTREACHED here when crbug.com/310972 is fixed.
+    return NULL;
+  }
+
+  // Load the given module for this NSS session.
+  static SECMODModule* LoadModule(const char* name,
+                                  const char* library_path,
+                                  const char* params) {
+    std::string modparams = base::StringPrintf(
+        "name=\"%s\" library=\"%s\" %s",
+        name, library_path, params ? params : "");
+
+    // Shouldn't need to const_cast here, but SECMOD doesn't properly
+    // declare input string arguments as const.  Bug
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=642546 was filed
+    // on NSS codebase to address this.
+    SECMODModule* module = SECMOD_LoadUserModule(
+        const_cast<char*>(modparams.c_str()), NULL, PR_FALSE);
+    if (!module) {
+      LOG(ERROR) << "Error loading " << name << " module into NSS: "
+                 << GetNSSErrorMessage();
+      return NULL;
+    }
+    if (!module->loaded) {
+      LOG(ERROR) << "After loading " << name << ", loaded==false: "
+                 << GetNSSErrorMessage();
+      SECMOD_DestroyModule(module);
+      return NULL;
+    }
+    return module;
+  }
+
+  bool tpm_token_enabled_for_nss_;
+  bool initializing_tpm_token_;
+  typedef std::vector<base::Closure> TPMReadyCallbackList;
+  TPMReadyCallbackList tpm_ready_callback_list_;
+  SECMODModule* chaps_module_;
+  crypto::ScopedPK11Slot tpm_slot_;
+  SECMODModule* root_;
+#if defined(OS_CHROMEOS)
+  typedef std::map<std::string, ChromeOSUserData*> ChromeOSUserMap;
+  ChromeOSUserMap chromeos_user_map_;
+  ScopedPK11Slot test_system_slot_;
+#endif
+#if defined(USE_NSS_CERTS)
+  // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011
+  // is fixed, we will no longer need the lock.
+  base::Lock write_lock_;
+#endif  // defined(USE_NSS_CERTS)
+
+  base::ThreadChecker thread_checker_;
+};
+
+base::LazyInstance<NSSInitSingleton>::Leaky
+    g_nss_singleton = LAZY_INSTANCE_INITIALIZER;
+}  // namespace
+
+#if defined(USE_NSS_CERTS)
+ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
+                                 const std::string& description) {
+  const std::string modspec =
+      base::StringPrintf("configDir='sql:%s' tokenDescription='%s'",
+                         path.value().c_str(),
+                         description.c_str());
+  PK11SlotInfo* db_slot = SECMOD_OpenUserDB(modspec.c_str());
+  if (db_slot) {
+    if (PK11_NeedUserInit(db_slot))
+      PK11_InitPin(db_slot, NULL, NULL);
+  } else {
+    LOG(ERROR) << "Error opening persistent database (" << modspec
+               << "): " << GetNSSErrorMessage();
+  }
+  return ScopedPK11Slot(db_slot);
+}
+
+void EarlySetupForNSSInit() {
+  base::FilePath database_dir = GetInitialConfigDirectory();
+  if (!database_dir.empty())
+    UseLocalCacheOfNSSDatabaseIfNFS(database_dir);
+}
+#endif
+
+void EnsureNSPRInit() {
+  g_nspr_singleton.Get();
+}
+
+void EnsureNSSInit() {
+  // Initializing SSL causes us to do blocking IO.
+  // Temporarily allow it until we fix
+  //   http://code.google.com/p/chromium/issues/detail?id=59847
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  g_nss_singleton.Get();
+}
+
+bool CheckNSSVersion(const char* version) {
+  return !!NSS_VersionCheck(version);
+}
+
+#if defined(USE_NSS_CERTS)
+base::Lock* GetNSSWriteLock() {
+  return g_nss_singleton.Get().write_lock();
+}
+
+AutoNSSWriteLock::AutoNSSWriteLock() : lock_(GetNSSWriteLock()) {
+  // May be NULL if the lock is not needed in our version of NSS.
+  if (lock_)
+    lock_->Acquire();
+}
+
+AutoNSSWriteLock::~AutoNSSWriteLock() {
+  if (lock_) {
+    lock_->AssertAcquired();
+    lock_->Release();
+  }
+}
+
+AutoSECMODListReadLock::AutoSECMODListReadLock()
+      : lock_(SECMOD_GetDefaultModuleListLock()) {
+    SECMOD_GetReadLock(lock_);
+  }
+
+AutoSECMODListReadLock::~AutoSECMODListReadLock() {
+  SECMOD_ReleaseReadLock(lock_);
+}
+#endif  // defined(USE_NSS_CERTS)
+
+#if defined(OS_CHROMEOS)
+ScopedPK11Slot GetSystemNSSKeySlot(
+    const base::Callback<void(ScopedPK11Slot)>& callback) {
+  return g_nss_singleton.Get().GetSystemNSSKeySlot(callback);
+}
+
+void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
+  g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot));
+}
+
+void EnableTPMTokenForNSS() {
+  g_nss_singleton.Get().EnableTPMTokenForNSS();
+}
+
+bool IsTPMTokenEnabledForNSS() {
+  return g_nss_singleton.Get().IsTPMTokenEnabledForNSS();
+}
+
+bool IsTPMTokenReady(const base::Closure& callback) {
+  return g_nss_singleton.Get().IsTPMTokenReady(callback);
+}
+
+void InitializeTPMTokenAndSystemSlot(
+    int token_slot_id,
+    const base::Callback<void(bool)>& callback) {
+  g_nss_singleton.Get().InitializeTPMTokenAndSystemSlot(token_slot_id,
+                                                        callback);
+}
+
+bool InitializeNSSForChromeOSUser(const std::string& username_hash,
+                                  const base::FilePath& path) {
+  return g_nss_singleton.Get().InitializeNSSForChromeOSUser(username_hash,
+                                                            path);
+}
+
+bool ShouldInitializeTPMForChromeOSUser(const std::string& username_hash) {
+  return g_nss_singleton.Get().ShouldInitializeTPMForChromeOSUser(
+      username_hash);
+}
+
+void WillInitializeTPMForChromeOSUser(const std::string& username_hash) {
+  g_nss_singleton.Get().WillInitializeTPMForChromeOSUser(username_hash);
+}
+
+void InitializeTPMForChromeOSUser(
+    const std::string& username_hash,
+    CK_SLOT_ID slot_id) {
+  g_nss_singleton.Get().InitializeTPMForChromeOSUser(username_hash, slot_id);
+}
+
+void InitializePrivateSoftwareSlotForChromeOSUser(
+    const std::string& username_hash) {
+  g_nss_singleton.Get().InitializePrivateSoftwareSlotForChromeOSUser(
+      username_hash);
+}
+
+ScopedPK11Slot GetPublicSlotForChromeOSUser(const std::string& username_hash) {
+  return g_nss_singleton.Get().GetPublicSlotForChromeOSUser(username_hash);
+}
+
+ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+    const std::string& username_hash,
+    const base::Callback<void(ScopedPK11Slot)>& callback) {
+  return g_nss_singleton.Get().GetPrivateSlotForChromeOSUser(username_hash,
+                                                             callback);
+}
+
+void CloseChromeOSUserForTesting(const std::string& username_hash) {
+  g_nss_singleton.Get().CloseChromeOSUserForTesting(username_hash);
+}
+#endif  // defined(OS_CHROMEOS)
+
+base::Time PRTimeToBaseTime(PRTime prtime) {
+  return base::Time::FromInternalValue(
+      prtime + base::Time::UnixEpoch().ToInternalValue());
+}
+
+PRTime BaseTimeToPRTime(base::Time time) {
+  return time.ToInternalValue() - base::Time::UnixEpoch().ToInternalValue();
+}
+
+#if !defined(OS_CHROMEOS)
+PK11SlotInfo* GetPersistentNSSKeySlot() {
+  return g_nss_singleton.Get().GetPersistentNSSKeySlot();
+}
+#endif
+
+}  // namespace crypto
diff --git a/libchrome/crypto/nss_util.h b/libchrome/crypto/nss_util.h
new file mode 100644
index 0000000..a8b57ff
--- /dev/null
+++ b/libchrome/crypto/nss_util.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_NSS_UTIL_H_
+#define CRYPTO_NSS_UTIL_H_
+
+#include <stdint.h>
+
+#include <string>
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "crypto/crypto_export.h"
+
+namespace base {
+class FilePath;
+class Lock;
+class Time;
+}  // namespace base
+
+// This file specifically doesn't depend on any NSS or NSPR headers because it
+// is included by various (non-crypto) parts of chrome to call the
+// initialization functions.
+namespace crypto {
+
+// EarlySetupForNSSInit performs lightweight setup which must occur before the
+// process goes multithreaded. This does not initialise NSS. For test, see
+// EnsureNSSInit.
+CRYPTO_EXPORT void EarlySetupForNSSInit();
+
+// Initialize NRPR if it isn't already initialized.  This function is
+// thread-safe, and NSPR will only ever be initialized once.
+CRYPTO_EXPORT void EnsureNSPRInit();
+
+// Initialize NSS if it isn't already initialized.  This must be called before
+// any other NSS functions.  This function is thread-safe, and NSS will only
+// ever be initialized once.
+CRYPTO_EXPORT void EnsureNSSInit();
+
+// Check if the current NSS version is greater than or equals to |version|.
+// A sample version string is "3.12.3".
+bool CheckNSSVersion(const char* version);
+
+#if defined(OS_CHROMEOS)
+// Indicates that NSS should use the Chaps library so that we
+// can access the TPM through NSS.  InitializeTPMTokenAndSystemSlot and
+// InitializeTPMForChromeOSUser must still be called to load the slots.
+CRYPTO_EXPORT void EnableTPMTokenForNSS();
+
+// Returns true if EnableTPMTokenForNSS has been called.
+CRYPTO_EXPORT bool IsTPMTokenEnabledForNSS();
+
+// Returns true if the TPM is owned and PKCS#11 initialized with the
+// user and security officer PINs, and has been enabled in NSS by
+// calling EnableTPMForNSS, and Chaps has been successfully
+// loaded into NSS.
+// If |callback| is non-null and the function returns false, the |callback| will
+// be run once the TPM is ready. |callback| will never be run if the function
+// returns true.
+CRYPTO_EXPORT bool IsTPMTokenReady(const base::Closure& callback)
+    WARN_UNUSED_RESULT;
+
+// Initialize the TPM token and system slot. The |callback| will run on the same
+// thread with true if the token and slot were successfully loaded or were
+// already initialized. |callback| will be passed false if loading failed.  Once
+// called, InitializeTPMTokenAndSystemSlot must not be called again until the
+// |callback| has been run.
+CRYPTO_EXPORT void InitializeTPMTokenAndSystemSlot(
+    int system_slot_id,
+    const base::Callback<void(bool)>& callback);
+#endif
+
+// Convert a NSS PRTime value into a base::Time object.
+// We use a int64_t instead of PRTime here to avoid depending on NSPR headers.
+CRYPTO_EXPORT base::Time PRTimeToBaseTime(int64_t prtime);
+
+// Convert a base::Time object into a PRTime value.
+// We use a int64_t instead of PRTime here to avoid depending on NSPR headers.
+CRYPTO_EXPORT int64_t BaseTimeToPRTime(base::Time time);
+
+// NSS has a bug which can cause a deadlock or stall in some cases when writing
+// to the certDB and keyDB. It also has a bug which causes concurrent key pair
+// generations to scribble over each other. To work around this, we synchronize
+// writes to the NSS databases with a global lock. The lock is hidden beneath a
+// function for easy disabling when the bug is fixed. Callers should allow for
+// it to return NULL in the future.
+//
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=564011
+base::Lock* GetNSSWriteLock();
+
+// A helper class that acquires the NSS write Lock while the AutoNSSWriteLock
+// is in scope.
+class CRYPTO_EXPORT AutoNSSWriteLock {
+ public:
+  AutoNSSWriteLock();
+  ~AutoNSSWriteLock();
+ private:
+  base::Lock *lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoNSSWriteLock);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_NSS_UTIL_H_
diff --git a/libchrome/crypto/nss_util_internal.h b/libchrome/crypto/nss_util_internal.h
new file mode 100644
index 0000000..697e376
--- /dev/null
+++ b/libchrome/crypto/nss_util_internal.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 CRYPTO_NSS_UTIL_INTERNAL_H_
+#define CRYPTO_NSS_UTIL_INTERNAL_H_
+
+#include <secmodt.h>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "crypto/crypto_export.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace base {
+class FilePath;
+}
+
+// These functions return a type defined in an NSS header, and so cannot be
+// declared in nss_util.h.  Hence, they are declared here.
+
+namespace crypto {
+
+// Opens an NSS software database in folder |path|, with the (potentially)
+// user-visible description |description|. Returns the slot for the opened
+// database, or nullptr if the database could not be opened.
+CRYPTO_EXPORT ScopedPK11Slot OpenSoftwareNSSDB(const base::FilePath& path,
+                                               const std::string& description);
+
+#if !defined(OS_CHROMEOS)
+// Returns a reference to the default NSS key slot for storing persistent data.
+// Caller must release returned reference with PK11_FreeSlot.
+CRYPTO_EXPORT PK11SlotInfo* GetPersistentNSSKeySlot() WARN_UNUSED_RESULT;
+#endif
+
+// A helper class that acquires the SECMOD list read lock while the
+// AutoSECMODListReadLock is in scope.
+class CRYPTO_EXPORT AutoSECMODListReadLock {
+ public:
+  AutoSECMODListReadLock();
+  ~AutoSECMODListReadLock();
+
+ private:
+  SECMODListLock* lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoSECMODListReadLock);
+};
+
+#if defined(OS_CHROMEOS)
+// Returns a reference to the system-wide TPM slot if it is loaded. If it is not
+// loaded and |callback| is non-null, the |callback| will be run once the slot
+// is loaded.
+CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot(
+    const base::Callback<void(ScopedPK11Slot)>& callback) WARN_UNUSED_RESULT;
+
+// Sets the test system slot to |slot|, which means that |slot| will be exposed
+// through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will return true.
+// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization,
+// does not have to be called if the test system slot is set.
+// This must must not be called consecutively with a |slot| != nullptr. If
+// |slot| is nullptr, the test system slot is unset.
+CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
+
+// Prepare per-user NSS slot mapping. It is safe to call this function multiple
+// times. Returns true if the user was added, or false if it already existed.
+CRYPTO_EXPORT bool InitializeNSSForChromeOSUser(
+    const std::string& username_hash,
+    const base::FilePath& path);
+
+// Returns whether TPM for ChromeOS user still needs initialization. If
+// true is returned, the caller can proceed to initialize TPM slot for the
+// user, but should call |WillInitializeTPMForChromeOSUser| first.
+// |InitializeNSSForChromeOSUser| must have been called first.
+CRYPTO_EXPORT bool ShouldInitializeTPMForChromeOSUser(
+    const std::string& username_hash) WARN_UNUSED_RESULT;
+
+// Makes |ShouldInitializeTPMForChromeOSUser| start returning false.
+// Should be called before starting TPM initialization for the user.
+// Assumes |InitializeNSSForChromeOSUser| had already been called.
+CRYPTO_EXPORT void WillInitializeTPMForChromeOSUser(
+    const std::string& username_hash);
+
+// Use TPM slot |slot_id| for user.  InitializeNSSForChromeOSUser must have been
+// called first.
+CRYPTO_EXPORT void InitializeTPMForChromeOSUser(
+    const std::string& username_hash,
+    CK_SLOT_ID slot_id);
+
+// Use the software slot as the private slot for user.
+// InitializeNSSForChromeOSUser must have been called first.
+CRYPTO_EXPORT void InitializePrivateSoftwareSlotForChromeOSUser(
+    const std::string& username_hash);
+
+// Returns a reference to the public slot for user.
+CRYPTO_EXPORT ScopedPK11Slot GetPublicSlotForChromeOSUser(
+    const std::string& username_hash) WARN_UNUSED_RESULT;
+
+// Returns the private slot for |username_hash| if it is loaded. If it is not
+// loaded and |callback| is non-null, the |callback| will be run once the slot
+// is loaded.
+CRYPTO_EXPORT ScopedPK11Slot GetPrivateSlotForChromeOSUser(
+    const std::string& username_hash,
+    const base::Callback<void(ScopedPK11Slot)>& callback) WARN_UNUSED_RESULT;
+
+// Closes the NSS DB for |username_hash| that was previously opened by the
+// *Initialize*ForChromeOSUser functions.
+CRYPTO_EXPORT void CloseChromeOSUserForTesting(
+    const std::string& username_hash);
+#endif  // defined(OS_CHROMEOS)
+
+}  // namespace crypto
+
+#endif  // CRYPTO_NSS_UTIL_INTERNAL_H_
diff --git a/libchrome/crypto/nss_util_unittest.cc b/libchrome/crypto/nss_util_unittest.cc
new file mode 100644
index 0000000..729d5bf
--- /dev/null
+++ b/libchrome/crypto/nss_util_unittest.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 "crypto/nss_util.h"
+
+#include <prtime.h>
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+TEST(NSSUtilTest, PRTimeConversion) {
+  EXPECT_EQ(base::Time::UnixEpoch(), PRTimeToBaseTime(0));
+  EXPECT_EQ(0, BaseTimeToPRTime(base::Time::UnixEpoch()));
+
+  PRExplodedTime prxtime;
+  prxtime.tm_params.tp_gmt_offset = 0;
+  prxtime.tm_params.tp_dst_offset = 0;
+  base::Time::Exploded exploded;
+  exploded.year = prxtime.tm_year = 2011;
+  exploded.month = 12;
+  prxtime.tm_month = 11;
+  // PRExplodedTime::tm_wday is a smaller type than Exploded::day_of_week, so
+  // assigning the two in this order instead of the reverse avoids potential
+  // warnings about type downcasting.
+  exploded.day_of_week = prxtime.tm_wday = 0;  // Should be unused.
+  exploded.day_of_month = prxtime.tm_mday = 10;
+  exploded.hour = prxtime.tm_hour = 2;
+  exploded.minute = prxtime.tm_min = 52;
+  exploded.second = prxtime.tm_sec = 19;
+  exploded.millisecond = 342;
+  prxtime.tm_usec = 342000;
+
+  PRTime pr_time = PR_ImplodeTime(&prxtime);
+  base::Time base_time;
+  EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &base_time));
+
+  EXPECT_EQ(base_time, PRTimeToBaseTime(pr_time));
+  EXPECT_EQ(pr_time, BaseTimeToPRTime(base_time));
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/openssl_bio_string.cc b/libchrome/crypto/openssl_bio_string.cc
new file mode 100644
index 0000000..4880500
--- /dev/null
+++ b/libchrome/crypto/openssl_bio_string.cc
@@ -0,0 +1,77 @@
+// 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 "crypto/openssl_bio_string.h"
+
+#include <openssl/bio.h>
+#include <string.h>
+
+namespace crypto {
+
+namespace {
+
+int bio_string_write(BIO* bio, const char* data, int len) {
+  reinterpret_cast<std::string*>(bio->ptr)->append(data, len);
+  return len;
+}
+
+int bio_string_puts(BIO* bio, const char* data) {
+  // Note: unlike puts(), BIO_puts does not add a newline.
+  return bio_string_write(bio, data, strlen(data));
+}
+
+long bio_string_ctrl(BIO* bio, int cmd, long num, void* ptr) {
+  std::string* str = reinterpret_cast<std::string*>(bio->ptr);
+  switch (cmd) {
+    case BIO_CTRL_RESET:
+      str->clear();
+      return 1;
+    case BIO_C_FILE_SEEK:
+      return -1;
+    case BIO_C_FILE_TELL:
+      return str->size();
+    case BIO_CTRL_FLUSH:
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+int bio_string_new(BIO* bio) {
+  bio->ptr = NULL;
+  bio->init = 0;
+  return 1;
+}
+
+int bio_string_free(BIO* bio) {
+  // The string is owned by the caller, so there's nothing to do here.
+  return bio != NULL;
+}
+
+BIO_METHOD bio_string_methods = {
+    // TODO(mattm): Should add some type number too? (bio.h uses 1-24)
+    BIO_TYPE_SOURCE_SINK,
+    "bio_string",
+    bio_string_write,
+    NULL, /* read */
+    bio_string_puts,
+    NULL, /* gets */
+    bio_string_ctrl,
+    bio_string_new,
+    bio_string_free,
+    NULL, /* callback_ctrl */
+};
+
+}  // namespace
+
+BIO* BIO_new_string(std::string* out) {
+  BIO* bio = BIO_new(&bio_string_methods);
+  if (!bio)
+    return bio;
+  bio->ptr = out;
+  bio->init = 1;
+  return bio;
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/openssl_bio_string.h b/libchrome/crypto/openssl_bio_string.h
new file mode 100644
index 0000000..ca46c12
--- /dev/null
+++ b/libchrome/crypto/openssl_bio_string.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 CRYPTO_OPENSSL_BIO_STRING_H_
+#define CRYPTO_OPENSSL_BIO_STRING_H_
+
+#include <string>
+
+#include "crypto/crypto_export.h"
+
+// From <openssl/bio.h>
+typedef struct bio_st BIO;
+
+namespace crypto {
+
+// Creates a new BIO that can be used with OpenSSL's various output functions,
+// and which will write all output directly into |out|. This is primarily
+// intended as a utility to reduce the amount of copying and separate
+// allocations when performing extensive string modifications or streaming
+// within OpenSSL.
+//
+// Note: |out| must remain valid for the duration of the BIO.
+CRYPTO_EXPORT BIO* BIO_new_string(std::string* out);
+
+}  // namespace crypto
+
+#endif  // CRYPTO_OPENSSL_BIO_STRING_H_
+
diff --git a/libchrome/crypto/openssl_bio_string_unittest.cc b/libchrome/crypto/openssl_bio_string_unittest.cc
new file mode 100644
index 0000000..9dfa0e7
--- /dev/null
+++ b/libchrome/crypto/openssl_bio_string_unittest.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 "crypto/openssl_bio_string.h"
+
+#include <openssl/bio.h>
+
+#include "crypto/scoped_openssl_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+TEST(OpenSSLBIOString, TestWrite) {
+  std::string s;
+  const std::string expected1("a one\nb 2\n");
+  const std::string expected2("c d e f");
+  const std::string expected3("g h i");
+  {
+    ScopedBIO bio(BIO_new_string(&s));
+    ASSERT_TRUE(bio.get());
+
+    EXPECT_EQ(static_cast<int>(expected1.size()),
+              BIO_printf(bio.get(), "a %s\nb %i\n", "one", 2));
+    EXPECT_EQ(expected1, s);
+
+    EXPECT_EQ(1, BIO_flush(bio.get()));
+    EXPECT_EQ(expected1, s);
+
+    EXPECT_EQ(static_cast<int>(expected2.size()),
+              BIO_write(bio.get(), expected2.data(), expected2.size()));
+    EXPECT_EQ(expected1 + expected2, s);
+
+    EXPECT_EQ(static_cast<int>(expected3.size()),
+              BIO_puts(bio.get(), expected3.c_str()));
+    EXPECT_EQ(expected1 + expected2 + expected3, s);
+  }
+  EXPECT_EQ(expected1 + expected2 + expected3, s);
+}
+
+TEST(OpenSSLBIOString, TestReset) {
+  std::string s;
+  const std::string expected1("a b c\n");
+  const std::string expected2("d e f g\n");
+  {
+    ScopedBIO bio(BIO_new_string(&s));
+    ASSERT_TRUE(bio.get());
+
+    EXPECT_EQ(static_cast<int>(expected1.size()),
+              BIO_write(bio.get(), expected1.data(), expected1.size()));
+    EXPECT_EQ(expected1, s);
+
+    EXPECT_EQ(1, BIO_reset(bio.get()));
+    EXPECT_EQ(std::string(), s);
+
+    EXPECT_EQ(static_cast<int>(expected2.size()),
+              BIO_write(bio.get(), expected2.data(), expected2.size()));
+    EXPECT_EQ(expected2, s);
+  }
+  EXPECT_EQ(expected2, s);
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/openssl_util.cc b/libchrome/crypto/openssl_util.cc
new file mode 100644
index 0000000..78c6cbb
--- /dev/null
+++ b/libchrome/crypto/openssl_util.cc
@@ -0,0 +1,64 @@
+// 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 "crypto/openssl_util.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/cpu.h>
+#else
+#include <openssl/ssl.h>
+#endif
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+
+namespace crypto {
+
+namespace {
+
+// Callback routine for OpenSSL to print error messages. |str| is a
+// NULL-terminated string of length |len| containing diagnostic information
+// such as the library, function and reason for the error, the file and line
+// where the error originated, plus potentially any context-specific
+// information about the error. |context| contains a pointer to user-supplied
+// data, which is currently unused.
+// If this callback returns a value <= 0, OpenSSL will stop processing the
+// error queue and return, otherwise it will continue calling this function
+// until all errors have been removed from the queue.
+int OpenSSLErrorCallback(const char* str, size_t len, void* context) {
+  DVLOG(1) << "\t" << base::StringPiece(str, len);
+  return 1;
+}
+
+}  // namespace
+
+void EnsureOpenSSLInit() {
+#if defined(OPENSSL_IS_BORINGSSL)
+  // CRYPTO_library_init may be safely called concurrently.
+  CRYPTO_library_init();
+#else
+  SSL_library_init();
+#endif
+}
+
+void ClearOpenSSLERRStack(const tracked_objects::Location& location) {
+  if (logging::DEBUG_MODE && VLOG_IS_ON(1)) {
+    uint32_t error_num = ERR_peek_error();
+    if (error_num == 0)
+      return;
+
+    std::string message;
+    location.Write(true, true, &message);
+    DVLOG(1) << "OpenSSL ERR_get_error stack from " << message;
+    ERR_print_errors_cb(&OpenSSLErrorCallback, NULL);
+  } else {
+    ERR_clear_error();
+  }
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/openssl_util.h b/libchrome/crypto/openssl_util.h
new file mode 100644
index 0000000..d608cde
--- /dev/null
+++ b/libchrome/crypto/openssl_util.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 CRYPTO_OPENSSL_UTIL_H_
+#define CRYPTO_OPENSSL_UTIL_H_
+
+#include <stddef.h>
+
+#include "base/location.h"
+#include "base/macros.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Provides a buffer of at least MIN_SIZE bytes, for use when calling OpenSSL's
+// SHA256, HMAC, etc functions, adapting the buffer sizing rules to meet those
+// of the our base wrapper APIs.
+// This allows the library to write directly to the caller's buffer if it is of
+// sufficient size, but if not it will write to temporary |min_sized_buffer_|
+// of required size and then its content is automatically copied out on
+// destruction, with truncation as appropriate.
+template<int MIN_SIZE>
+class ScopedOpenSSLSafeSizeBuffer {
+ public:
+  ScopedOpenSSLSafeSizeBuffer(unsigned char* output, size_t output_len)
+      : output_(output),
+        output_len_(output_len) {
+  }
+
+  ~ScopedOpenSSLSafeSizeBuffer() {
+    if (output_len_ < MIN_SIZE) {
+      // Copy the temporary buffer out, truncating as needed.
+      memcpy(output_, min_sized_buffer_, output_len_);
+    }
+    // else... any writing already happened directly into |output_|.
+  }
+
+  unsigned char* safe_buffer() {
+    return output_len_ < MIN_SIZE ? min_sized_buffer_ : output_;
+  }
+
+ private:
+  // Pointer to the caller's data area and its associated size, where data
+  // written via safe_buffer() will [eventually] end up.
+  unsigned char* output_;
+  size_t output_len_;
+
+  // Temporary buffer writen into in the case where the caller's
+  // buffer is not of sufficient size.
+  unsigned char min_sized_buffer_[MIN_SIZE];
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedOpenSSLSafeSizeBuffer);
+};
+
+// Initialize OpenSSL if it isn't already initialized. This must be called
+// before any other OpenSSL functions though it is safe and cheap to call this
+// multiple times.
+// This function is thread-safe, and OpenSSL will only ever be initialized once.
+// OpenSSL will be properly shut down on program exit.
+CRYPTO_EXPORT void EnsureOpenSSLInit();
+
+// Drains the OpenSSL ERR_get_error stack. On a debug build the error codes
+// are send to VLOG(1), on a release build they are disregarded. In most
+// cases you should pass FROM_HERE as the |location|.
+CRYPTO_EXPORT void ClearOpenSSLERRStack(
+    const tracked_objects::Location& location);
+
+// Place an instance of this class on the call stack to automatically clear
+// the OpenSSL error stack on function exit.
+class OpenSSLErrStackTracer {
+ public:
+  // Pass FROM_HERE as |location|, to help track the source of OpenSSL error
+  // messages. Note any diagnostic emitted will be tagged with the location of
+  // the constructor call as it's not possible to trace a destructor's callsite.
+  explicit OpenSSLErrStackTracer(const tracked_objects::Location& location)
+      : location_(location) {
+    EnsureOpenSSLInit();
+  }
+  ~OpenSSLErrStackTracer() {
+    ClearOpenSSLERRStack(location_);
+  }
+
+ private:
+  const tracked_objects::Location location_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(OpenSSLErrStackTracer);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_OPENSSL_UTIL_H_
diff --git a/libchrome/crypto/p224.cc b/libchrome/crypto/p224.cc
new file mode 100644
index 0000000..685a335
--- /dev/null
+++ b/libchrome/crypto/p224.cc
@@ -0,0 +1,747 @@
+// Copyright (c) 2012 The Chromium 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 an implementation of the P224 elliptic curve group. It's written to
+// be short and simple rather than fast, although it's still constant-time.
+//
+// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
+
+#include "crypto/p224.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "base/sys_byteorder.h"
+
+namespace {
+
+using base::HostToNet32;
+using base::NetToHost32;
+
+// Field element functions.
+//
+// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1.
+//
+// Field elements are represented by a FieldElement, which is a typedef to an
+// array of 8 uint32_t's. The value of a FieldElement, a, is:
+//   a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7]
+//
+// Using 28-bit limbs means that there's only 4 bits of headroom, which is less
+// than we would really like. But it has the useful feature that we hit 2**224
+// exactly, making the reflections during a reduce much nicer.
+
+using crypto::p224::FieldElement;
+
+// kP is the P224 prime.
+const FieldElement kP = {
+  1, 0, 0, 268431360,
+  268435455, 268435455, 268435455, 268435455,
+};
+
+void Contract(FieldElement* inout);
+
+// IsZero returns 0xffffffff if a == 0 mod p and 0 otherwise.
+uint32_t IsZero(const FieldElement& a) {
+  FieldElement minimal;
+  memcpy(&minimal, &a, sizeof(minimal));
+  Contract(&minimal);
+
+  uint32_t is_zero = 0, is_p = 0;
+  for (unsigned i = 0; i < 8; i++) {
+    is_zero |= minimal[i];
+    is_p |= minimal[i] - kP[i];
+  }
+
+  // If either is_zero or is_p is 0, then we should return 1.
+  is_zero |= is_zero >> 16;
+  is_zero |= is_zero >> 8;
+  is_zero |= is_zero >> 4;
+  is_zero |= is_zero >> 2;
+  is_zero |= is_zero >> 1;
+
+  is_p |= is_p >> 16;
+  is_p |= is_p >> 8;
+  is_p |= is_p >> 4;
+  is_p |= is_p >> 2;
+  is_p |= is_p >> 1;
+
+  // For is_zero and is_p, the LSB is 0 iff all the bits are zero.
+  is_zero &= is_p & 1;
+  is_zero = (~is_zero) << 31;
+  is_zero = static_cast<int32_t>(is_zero) >> 31;
+  return is_zero;
+}
+
+// Add computes *out = a+b
+//
+// a[i] + b[i] < 2**32
+void Add(FieldElement* out, const FieldElement& a, const FieldElement& b) {
+  for (int i = 0; i < 8; i++) {
+    (*out)[i] = a[i] + b[i];
+  }
+}
+
+static const uint32_t kTwo31p3 = (1u << 31) + (1u << 3);
+static const uint32_t kTwo31m3 = (1u << 31) - (1u << 3);
+static const uint32_t kTwo31m15m3 = (1u << 31) - (1u << 15) - (1u << 3);
+// kZero31ModP is 0 mod p where bit 31 is set in all limbs so that we can
+// subtract smaller amounts without underflow. See the section "Subtraction" in
+// [1] for why.
+static const FieldElement kZero31ModP = {
+  kTwo31p3, kTwo31m3, kTwo31m3, kTwo31m15m3,
+  kTwo31m3, kTwo31m3, kTwo31m3, kTwo31m3
+};
+
+// Subtract computes *out = a-b
+//
+// a[i], b[i] < 2**30
+// out[i] < 2**32
+void Subtract(FieldElement* out, const FieldElement& a, const FieldElement& b) {
+  for (int i = 0; i < 8; i++) {
+    // See the section on "Subtraction" in [1] for details.
+    (*out)[i] = a[i] + kZero31ModP[i] - b[i];
+  }
+}
+
+static const uint64_t kTwo63p35 = (1ull << 63) + (1ull << 35);
+static const uint64_t kTwo63m35 = (1ull << 63) - (1ull << 35);
+static const uint64_t kTwo63m35m19 = (1ull << 63) - (1ull << 35) - (1ull << 19);
+// kZero63ModP is 0 mod p where bit 63 is set in all limbs. See the section
+// "Subtraction" in [1] for why.
+static const uint64_t kZero63ModP[8] = {
+    kTwo63p35,    kTwo63m35, kTwo63m35, kTwo63m35,
+    kTwo63m35m19, kTwo63m35, kTwo63m35, kTwo63m35,
+};
+
+static const uint32_t kBottom28Bits = 0xfffffff;
+
+// LargeFieldElement also represents an element of the field. The limbs are
+// still spaced 28-bits apart and in little-endian order. So the limbs are at
+// 0, 28, 56, ..., 392 bits, each 64-bits wide.
+typedef uint64_t LargeFieldElement[15];
+
+// ReduceLarge converts a LargeFieldElement to a FieldElement.
+//
+// in[i] < 2**62
+void ReduceLarge(FieldElement* out, LargeFieldElement* inptr) {
+  LargeFieldElement& in(*inptr);
+
+  for (int i = 0; i < 8; i++) {
+    in[i] += kZero63ModP[i];
+  }
+
+  // Eliminate the coefficients at 2**224 and greater while maintaining the
+  // same value mod p.
+  for (int i = 14; i >= 8; i--) {
+    in[i-8] -= in[i];  // reflection off the "+1" term of p.
+    in[i-5] += (in[i] & 0xffff) << 12;  // part of the "-2**96" reflection.
+    in[i-4] += in[i] >> 16;  // the rest of the "-2**96" reflection.
+  }
+  in[8] = 0;
+  // in[0..8] < 2**64
+
+  // As the values become small enough, we start to store them in |out| and use
+  // 32-bit operations.
+  for (int i = 1; i < 8; i++) {
+    in[i+1] += in[i] >> 28;
+    (*out)[i] = static_cast<uint32_t>(in[i] & kBottom28Bits);
+  }
+  // Eliminate the term at 2*224 that we introduced while keeping the same
+  // value mod p.
+  in[0] -= in[8];  // reflection off the "+1" term of p.
+  (*out)[3] += static_cast<uint32_t>(in[8] & 0xffff) << 12;  // "-2**96" term
+  (*out)[4] += static_cast<uint32_t>(in[8] >> 16);  // rest of "-2**96" term
+  // in[0] < 2**64
+  // out[3] < 2**29
+  // out[4] < 2**29
+  // out[1,2,5..7] < 2**28
+
+  (*out)[0] = static_cast<uint32_t>(in[0] & kBottom28Bits);
+  (*out)[1] += static_cast<uint32_t>((in[0] >> 28) & kBottom28Bits);
+  (*out)[2] += static_cast<uint32_t>(in[0] >> 56);
+  // out[0] < 2**28
+  // out[1..4] < 2**29
+  // out[5..7] < 2**28
+}
+
+// Mul computes *out = a*b
+//
+// a[i] < 2**29, b[i] < 2**30 (or vice versa)
+// out[i] < 2**29
+void Mul(FieldElement* out, const FieldElement& a, const FieldElement& b) {
+  LargeFieldElement tmp;
+  memset(&tmp, 0, sizeof(tmp));
+
+  for (int i = 0; i < 8; i++) {
+    for (int j = 0; j < 8; j++) {
+      tmp[i + j] += static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(b[j]);
+    }
+  }
+
+  ReduceLarge(out, &tmp);
+}
+
+// Square computes *out = a*a
+//
+// a[i] < 2**29
+// out[i] < 2**29
+void Square(FieldElement* out, const FieldElement& a) {
+  LargeFieldElement tmp;
+  memset(&tmp, 0, sizeof(tmp));
+
+  for (int i = 0; i < 8; i++) {
+    for (int j = 0; j <= i; j++) {
+      uint64_t r = static_cast<uint64_t>(a[i]) * static_cast<uint64_t>(a[j]);
+      if (i == j) {
+        tmp[i+j] += r;
+      } else {
+        tmp[i+j] += r << 1;
+      }
+    }
+  }
+
+  ReduceLarge(out, &tmp);
+}
+
+// Reduce reduces the coefficients of in_out to smaller bounds.
+//
+// On entry: a[i] < 2**31 + 2**30
+// On exit: a[i] < 2**29
+void Reduce(FieldElement* in_out) {
+  FieldElement& a = *in_out;
+
+  for (int i = 0; i < 7; i++) {
+    a[i+1] += a[i] >> 28;
+    a[i] &= kBottom28Bits;
+  }
+  uint32_t top = a[7] >> 28;
+  a[7] &= kBottom28Bits;
+
+  // top < 2**4
+  // Constant-time: mask = (top != 0) ? 0xffffffff : 0
+  uint32_t mask = top;
+  mask |= mask >> 2;
+  mask |= mask >> 1;
+  mask <<= 31;
+  mask = static_cast<uint32_t>(static_cast<int32_t>(mask) >> 31);
+
+  // Eliminate top while maintaining the same value mod p.
+  a[0] -= top;
+  a[3] += top << 12;
+
+  // We may have just made a[0] negative but, if we did, then we must
+  // have added something to a[3], thus it's > 2**12. Therefore we can
+  // carry down to a[0].
+  a[3] -= 1 & mask;
+  a[2] += mask & ((1<<28) - 1);
+  a[1] += mask & ((1<<28) - 1);
+  a[0] += mask & (1<<28);
+}
+
+// Invert calcuates *out = in**-1 by computing in**(2**224 - 2**96 - 1), i.e.
+// Fermat's little theorem.
+void Invert(FieldElement* out, const FieldElement& in) {
+  FieldElement f1, f2, f3, f4;
+
+  Square(&f1, in);                        // 2
+  Mul(&f1, f1, in);                       // 2**2 - 1
+  Square(&f1, f1);                        // 2**3 - 2
+  Mul(&f1, f1, in);                       // 2**3 - 1
+  Square(&f2, f1);                        // 2**4 - 2
+  Square(&f2, f2);                        // 2**5 - 4
+  Square(&f2, f2);                        // 2**6 - 8
+  Mul(&f1, f1, f2);                       // 2**6 - 1
+  Square(&f2, f1);                        // 2**7 - 2
+  for (int i = 0; i < 5; i++) {           // 2**12 - 2**6
+    Square(&f2, f2);
+  }
+  Mul(&f2, f2, f1);                       // 2**12 - 1
+  Square(&f3, f2);                        // 2**13 - 2
+  for (int i = 0; i < 11; i++) {          // 2**24 - 2**12
+    Square(&f3, f3);
+  }
+  Mul(&f2, f3, f2);                       // 2**24 - 1
+  Square(&f3, f2);                        // 2**25 - 2
+  for (int i = 0; i < 23; i++) {          // 2**48 - 2**24
+    Square(&f3, f3);
+  }
+  Mul(&f3, f3, f2);                       // 2**48 - 1
+  Square(&f4, f3);                        // 2**49 - 2
+  for (int i = 0; i < 47; i++) {          // 2**96 - 2**48
+    Square(&f4, f4);
+  }
+  Mul(&f3, f3, f4);                       // 2**96 - 1
+  Square(&f4, f3);                        // 2**97 - 2
+  for (int i = 0; i < 23; i++) {          // 2**120 - 2**24
+    Square(&f4, f4);
+  }
+  Mul(&f2, f4, f2);                       // 2**120 - 1
+  for (int i = 0; i < 6; i++) {           // 2**126 - 2**6
+    Square(&f2, f2);
+  }
+  Mul(&f1, f1, f2);                       // 2**126 - 1
+  Square(&f1, f1);                        // 2**127 - 2
+  Mul(&f1, f1, in);                       // 2**127 - 1
+  for (int i = 0; i < 97; i++) {          // 2**224 - 2**97
+    Square(&f1, f1);
+  }
+  Mul(out, f1, f3);                       // 2**224 - 2**96 - 1
+}
+
+// Contract converts a FieldElement to its minimal, distinguished form.
+//
+// On entry, in[i] < 2**29
+// On exit, in[i] < 2**28
+void Contract(FieldElement* inout) {
+  FieldElement& out = *inout;
+
+  // Reduce the coefficients to < 2**28.
+  for (int i = 0; i < 7; i++) {
+    out[i+1] += out[i] >> 28;
+    out[i] &= kBottom28Bits;
+  }
+  uint32_t top = out[7] >> 28;
+  out[7] &= kBottom28Bits;
+
+  // Eliminate top while maintaining the same value mod p.
+  out[0] -= top;
+  out[3] += top << 12;
+
+  // We may just have made out[0] negative. So we carry down. If we made
+  // out[0] negative then we know that out[3] is sufficiently positive
+  // because we just added to it.
+  for (int i = 0; i < 3; i++) {
+    uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31);
+    out[i] += (1 << 28) & mask;
+    out[i+1] -= 1 & mask;
+  }
+
+  // We might have pushed out[3] over 2**28 so we perform another, partial
+  // carry chain.
+  for (int i = 3; i < 7; i++) {
+    out[i+1] += out[i] >> 28;
+    out[i] &= kBottom28Bits;
+  }
+  top = out[7] >> 28;
+  out[7] &= kBottom28Bits;
+
+  // Eliminate top while maintaining the same value mod p.
+  out[0] -= top;
+  out[3] += top << 12;
+
+  // There are two cases to consider for out[3]:
+  //   1) The first time that we eliminated top, we didn't push out[3] over
+  //      2**28. In this case, the partial carry chain didn't change any values
+  //      and top is zero.
+  //   2) We did push out[3] over 2**28 the first time that we eliminated top.
+  //      The first value of top was in [0..16), therefore, prior to eliminating
+  //      the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
+  //      overflowing and being reduced by the second carry chain, out[3] <=
+  //      0xf000. Thus it cannot have overflowed when we eliminated top for the
+  //      second time.
+
+  // Again, we may just have made out[0] negative, so do the same carry down.
+  // As before, if we made out[0] negative then we know that out[3] is
+  // sufficiently positive.
+  for (int i = 0; i < 3; i++) {
+    uint32_t mask = static_cast<uint32_t>(static_cast<int32_t>(out[i]) >> 31);
+    out[i] += (1 << 28) & mask;
+    out[i+1] -= 1 & mask;
+  }
+
+  // The value is < 2**224, but maybe greater than p. In order to reduce to a
+  // unique, minimal value we see if the value is >= p and, if so, subtract p.
+
+  // First we build a mask from the top four limbs, which must all be
+  // equal to bottom28Bits if the whole value is >= p. If top_4_all_ones
+  // ends up with any zero bits in the bottom 28 bits, then this wasn't
+  // true.
+  uint32_t top_4_all_ones = 0xffffffffu;
+  for (int i = 4; i < 8; i++) {
+    top_4_all_ones &= out[i];
+  }
+  top_4_all_ones |= 0xf0000000;
+  // Now we replicate any zero bits to all the bits in top_4_all_ones.
+  top_4_all_ones &= top_4_all_ones >> 16;
+  top_4_all_ones &= top_4_all_ones >> 8;
+  top_4_all_ones &= top_4_all_ones >> 4;
+  top_4_all_ones &= top_4_all_ones >> 2;
+  top_4_all_ones &= top_4_all_ones >> 1;
+  top_4_all_ones =
+      static_cast<uint32_t>(static_cast<int32_t>(top_4_all_ones << 31) >> 31);
+
+  // Now we test whether the bottom three limbs are non-zero.
+  uint32_t bottom_3_non_zero = out[0] | out[1] | out[2];
+  bottom_3_non_zero |= bottom_3_non_zero >> 16;
+  bottom_3_non_zero |= bottom_3_non_zero >> 8;
+  bottom_3_non_zero |= bottom_3_non_zero >> 4;
+  bottom_3_non_zero |= bottom_3_non_zero >> 2;
+  bottom_3_non_zero |= bottom_3_non_zero >> 1;
+  bottom_3_non_zero =
+      static_cast<uint32_t>(static_cast<int32_t>(bottom_3_non_zero) >> 31);
+
+  // Everything depends on the value of out[3].
+  //    If it's > 0xffff000 and top_4_all_ones != 0 then the whole value is >= p
+  //    If it's = 0xffff000 and top_4_all_ones != 0 and bottom_3_non_zero != 0,
+  //      then the whole value is >= p
+  //    If it's < 0xffff000, then the whole value is < p
+  uint32_t n = out[3] - 0xffff000;
+  uint32_t out_3_equal = n;
+  out_3_equal |= out_3_equal >> 16;
+  out_3_equal |= out_3_equal >> 8;
+  out_3_equal |= out_3_equal >> 4;
+  out_3_equal |= out_3_equal >> 2;
+  out_3_equal |= out_3_equal >> 1;
+  out_3_equal =
+      ~static_cast<uint32_t>(static_cast<int32_t>(out_3_equal << 31) >> 31);
+
+  // If out[3] > 0xffff000 then n's MSB will be zero.
+  uint32_t out_3_gt =
+      ~static_cast<uint32_t>(static_cast<int32_t>(n << 31) >> 31);
+
+  uint32_t mask =
+      top_4_all_ones & ((out_3_equal & bottom_3_non_zero) | out_3_gt);
+  out[0] -= 1 & mask;
+  out[3] -= 0xffff000 & mask;
+  out[4] -= 0xfffffff & mask;
+  out[5] -= 0xfffffff & mask;
+  out[6] -= 0xfffffff & mask;
+  out[7] -= 0xfffffff & mask;
+}
+
+
+// Group element functions.
+//
+// These functions deal with group elements. The group is an elliptic curve
+// group with a = -3 defined in FIPS 186-3, section D.2.2.
+
+using crypto::p224::Point;
+
+// kB is parameter of the elliptic curve.
+const FieldElement kB = {
+  55967668, 11768882, 265861671, 185302395,
+  39211076, 180311059, 84673715, 188764328,
+};
+
+void CopyConditional(Point* out, const Point& a, uint32_t mask);
+void DoubleJacobian(Point* out, const Point& a);
+
+// AddJacobian computes *out = a+b where a != b.
+void AddJacobian(Point *out,
+                 const Point& a,
+                 const Point& b) {
+  // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
+  FieldElement z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v;
+
+  uint32_t z1_is_zero = IsZero(a.z);
+  uint32_t z2_is_zero = IsZero(b.z);
+
+  // Z1Z1 = Z1²
+  Square(&z1z1, a.z);
+
+  // Z2Z2 = Z2²
+  Square(&z2z2, b.z);
+
+  // U1 = X1*Z2Z2
+  Mul(&u1, a.x, z2z2);
+
+  // U2 = X2*Z1Z1
+  Mul(&u2, b.x, z1z1);
+
+  // S1 = Y1*Z2*Z2Z2
+  Mul(&s1, b.z, z2z2);
+  Mul(&s1, a.y, s1);
+
+  // S2 = Y2*Z1*Z1Z1
+  Mul(&s2, a.z, z1z1);
+  Mul(&s2, b.y, s2);
+
+  // H = U2-U1
+  Subtract(&h, u2, u1);
+  Reduce(&h);
+  uint32_t x_equal = IsZero(h);
+
+  // I = (2*H)²
+  for (int k = 0; k < 8; k++) {
+    i[k] = h[k] << 1;
+  }
+  Reduce(&i);
+  Square(&i, i);
+
+  // J = H*I
+  Mul(&j, h, i);
+  // r = 2*(S2-S1)
+  Subtract(&r, s2, s1);
+  Reduce(&r);
+  uint32_t y_equal = IsZero(r);
+
+  if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) {
+    // The two input points are the same therefore we must use the dedicated
+    // doubling function as the slope of the line is undefined.
+    DoubleJacobian(out, a);
+    return;
+  }
+
+  for (int k = 0; k < 8; k++) {
+    r[k] <<= 1;
+  }
+  Reduce(&r);
+
+  // V = U1*I
+  Mul(&v, u1, i);
+
+  // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H
+  Add(&z1z1, z1z1, z2z2);
+  Add(&z2z2, a.z, b.z);
+  Reduce(&z2z2);
+  Square(&z2z2, z2z2);
+  Subtract(&out->z, z2z2, z1z1);
+  Reduce(&out->z);
+  Mul(&out->z, out->z, h);
+
+  // X3 = r²-J-2*V
+  for (int k = 0; k < 8; k++) {
+    z1z1[k] = v[k] << 1;
+  }
+  Add(&z1z1, j, z1z1);
+  Reduce(&z1z1);
+  Square(&out->x, r);
+  Subtract(&out->x, out->x, z1z1);
+  Reduce(&out->x);
+
+  // Y3 = r*(V-X3)-2*S1*J
+  for (int k = 0; k < 8; k++) {
+    s1[k] <<= 1;
+  }
+  Mul(&s1, s1, j);
+  Subtract(&z1z1, v, out->x);
+  Reduce(&z1z1);
+  Mul(&z1z1, z1z1, r);
+  Subtract(&out->y, z1z1, s1);
+  Reduce(&out->y);
+
+  CopyConditional(out, a, z2_is_zero);
+  CopyConditional(out, b, z1_is_zero);
+}
+
+// DoubleJacobian computes *out = a+a.
+void DoubleJacobian(Point* out, const Point& a) {
+  // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
+  FieldElement delta, gamma, beta, alpha, t;
+
+  Square(&delta, a.z);
+  Square(&gamma, a.y);
+  Mul(&beta, a.x, gamma);
+
+  // alpha = 3*(X1-delta)*(X1+delta)
+  Add(&t, a.x, delta);
+  for (int i = 0; i < 8; i++) {
+          t[i] += t[i] << 1;
+  }
+  Reduce(&t);
+  Subtract(&alpha, a.x, delta);
+  Reduce(&alpha);
+  Mul(&alpha, alpha, t);
+
+  // Z3 = (Y1+Z1)²-gamma-delta
+  Add(&out->z, a.y, a.z);
+  Reduce(&out->z);
+  Square(&out->z, out->z);
+  Subtract(&out->z, out->z, gamma);
+  Reduce(&out->z);
+  Subtract(&out->z, out->z, delta);
+  Reduce(&out->z);
+
+  // X3 = alpha²-8*beta
+  for (int i = 0; i < 8; i++) {
+          delta[i] = beta[i] << 3;
+  }
+  Reduce(&delta);
+  Square(&out->x, alpha);
+  Subtract(&out->x, out->x, delta);
+  Reduce(&out->x);
+
+  // Y3 = alpha*(4*beta-X3)-8*gamma²
+  for (int i = 0; i < 8; i++) {
+          beta[i] <<= 2;
+  }
+  Reduce(&beta);
+  Subtract(&beta, beta, out->x);
+  Reduce(&beta);
+  Square(&gamma, gamma);
+  for (int i = 0; i < 8; i++) {
+          gamma[i] <<= 3;
+  }
+  Reduce(&gamma);
+  Mul(&out->y, alpha, beta);
+  Subtract(&out->y, out->y, gamma);
+  Reduce(&out->y);
+}
+
+// CopyConditional sets *out=a if mask is 0xffffffff. mask must be either 0 of
+// 0xffffffff.
+void CopyConditional(Point* out, const Point& a, uint32_t mask) {
+  for (int i = 0; i < 8; i++) {
+    out->x[i] ^= mask & (a.x[i] ^ out->x[i]);
+    out->y[i] ^= mask & (a.y[i] ^ out->y[i]);
+    out->z[i] ^= mask & (a.z[i] ^ out->z[i]);
+  }
+}
+
+// ScalarMult calculates *out = a*scalar where scalar is a big-endian number of
+// length scalar_len and != 0.
+void ScalarMult(Point* out,
+                const Point& a,
+                const uint8_t* scalar,
+                size_t scalar_len) {
+  memset(out, 0, sizeof(*out));
+  Point tmp;
+
+  for (size_t i = 0; i < scalar_len; i++) {
+    for (unsigned int bit_num = 0; bit_num < 8; bit_num++) {
+      DoubleJacobian(out, *out);
+      uint32_t bit = static_cast<uint32_t>(static_cast<int32_t>(
+          (((scalar[i] >> (7 - bit_num)) & 1) << 31) >> 31));
+      AddJacobian(&tmp, a, *out);
+      CopyConditional(out, tmp, bit);
+    }
+  }
+}
+
+// Get224Bits reads 7 words from in and scatters their contents in
+// little-endian form into 8 words at out, 28 bits per output word.
+void Get224Bits(uint32_t* out, const uint32_t* in) {
+  out[0] = NetToHost32(in[6]) & kBottom28Bits;
+  out[1] = ((NetToHost32(in[5]) << 4) |
+            (NetToHost32(in[6]) >> 28)) & kBottom28Bits;
+  out[2] = ((NetToHost32(in[4]) << 8) |
+            (NetToHost32(in[5]) >> 24)) & kBottom28Bits;
+  out[3] = ((NetToHost32(in[3]) << 12) |
+            (NetToHost32(in[4]) >> 20)) & kBottom28Bits;
+  out[4] = ((NetToHost32(in[2]) << 16) |
+            (NetToHost32(in[3]) >> 16)) & kBottom28Bits;
+  out[5] = ((NetToHost32(in[1]) << 20) |
+            (NetToHost32(in[2]) >> 12)) & kBottom28Bits;
+  out[6] = ((NetToHost32(in[0]) << 24) |
+            (NetToHost32(in[1]) >> 8)) & kBottom28Bits;
+  out[7] = (NetToHost32(in[0]) >> 4) & kBottom28Bits;
+}
+
+// Put224Bits performs the inverse operation to Get224Bits: taking 28 bits from
+// each of 8 input words and writing them in big-endian order to 7 words at
+// out.
+void Put224Bits(uint32_t* out, const uint32_t* in) {
+  out[6] = HostToNet32((in[0] >> 0) | (in[1] << 28));
+  out[5] = HostToNet32((in[1] >> 4) | (in[2] << 24));
+  out[4] = HostToNet32((in[2] >> 8) | (in[3] << 20));
+  out[3] = HostToNet32((in[3] >> 12) | (in[4] << 16));
+  out[2] = HostToNet32((in[4] >> 16) | (in[5] << 12));
+  out[1] = HostToNet32((in[5] >> 20) | (in[6] << 8));
+  out[0] = HostToNet32((in[6] >> 24) | (in[7] << 4));
+}
+
+}  // anonymous namespace
+
+namespace crypto {
+
+namespace p224 {
+
+bool Point::SetFromString(const base::StringPiece& in) {
+  if (in.size() != 2*28)
+    return false;
+  const uint32_t* inwords = reinterpret_cast<const uint32_t*>(in.data());
+  Get224Bits(x, inwords);
+  Get224Bits(y, inwords + 7);
+  memset(&z, 0, sizeof(z));
+  z[0] = 1;
+
+  // Check that the point is on the curve, i.e. that y² = x³ - 3x + b.
+  FieldElement lhs;
+  Square(&lhs, y);
+  Contract(&lhs);
+
+  FieldElement rhs;
+  Square(&rhs, x);
+  Mul(&rhs, x, rhs);
+
+  FieldElement three_x;
+  for (int i = 0; i < 8; i++) {
+    three_x[i] = x[i] * 3;
+  }
+  Reduce(&three_x);
+  Subtract(&rhs, rhs, three_x);
+  Reduce(&rhs);
+
+  ::Add(&rhs, rhs, kB);
+  Contract(&rhs);
+  return memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
+}
+
+std::string Point::ToString() const {
+  FieldElement zinv, zinv_sq, xx, yy;
+
+  // If this is the point at infinity we return a string of all zeros.
+  if (IsZero(this->z)) {
+    static const char zeros[56] = {0};
+    return std::string(zeros, sizeof(zeros));
+  }
+
+  Invert(&zinv, this->z);
+  Square(&zinv_sq, zinv);
+  Mul(&xx, x, zinv_sq);
+  Mul(&zinv_sq, zinv_sq, zinv);
+  Mul(&yy, y, zinv_sq);
+
+  Contract(&xx);
+  Contract(&yy);
+
+  uint32_t outwords[14];
+  Put224Bits(outwords, xx);
+  Put224Bits(outwords + 7, yy);
+  return std::string(reinterpret_cast<const char*>(outwords), sizeof(outwords));
+}
+
+void ScalarMult(const Point& in, const uint8_t* scalar, Point* out) {
+  ::ScalarMult(out, in, scalar, 28);
+}
+
+// kBasePoint is the base point (generator) of the elliptic curve group.
+static const Point kBasePoint = {
+  {22813985, 52956513, 34677300, 203240812,
+   12143107, 133374265, 225162431, 191946955},
+  {83918388, 223877528, 122119236, 123340192,
+   266784067, 263504429, 146143011, 198407736},
+  {1, 0, 0, 0, 0, 0, 0, 0},
+};
+
+void ScalarBaseMult(const uint8_t* scalar, Point* out) {
+  ::ScalarMult(out, kBasePoint, scalar, 28);
+}
+
+void Add(const Point& a, const Point& b, Point* out) {
+  AddJacobian(out, a, b);
+}
+
+void Negate(const Point& in, Point* out) {
+  // Guide to elliptic curve cryptography, page 89 suggests that (X : X+Y : Z)
+  // is the negative in Jacobian coordinates, but it doesn't actually appear to
+  // be true in testing so this performs the negation in affine coordinates.
+  FieldElement zinv, zinv_sq, y;
+  Invert(&zinv, in.z);
+  Square(&zinv_sq, zinv);
+  Mul(&out->x, in.x, zinv_sq);
+  Mul(&zinv_sq, zinv_sq, zinv);
+  Mul(&y, in.y, zinv_sq);
+
+  Subtract(&out->y, kP, y);
+  Reduce(&out->y);
+
+  memset(&out->z, 0, sizeof(out->z));
+  out->z[0] = 1;
+}
+
+}  // namespace p224
+
+}  // namespace crypto
diff --git a/libchrome/crypto/p224.h b/libchrome/crypto/p224.h
new file mode 100644
index 0000000..e9a53a9
--- /dev/null
+++ b/libchrome/crypto/p224.h
@@ -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.
+
+#ifndef CRYPTO_P224_H_
+#define CRYPTO_P224_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// P224 implements an elliptic curve group, commonly known as P224 and defined
+// in FIPS 186-3, section D.2.2.
+namespace p224 {
+
+// An element of the field (ℤ/pℤ) is represented with 8, 28-bit limbs in
+// little endian order.
+typedef uint32_t FieldElement[8];
+
+struct CRYPTO_EXPORT Point {
+  // SetFromString the value of the point from the 56 byte, external
+  // representation. The external point representation is an (x, y) pair of a
+  // point on the curve. Each field element is represented as a big-endian
+  // number < p.
+  bool SetFromString(const base::StringPiece& in);
+
+  // ToString returns an external representation of the Point.
+  std::string ToString() const;
+
+  // An Point is represented in Jacobian form (x/z², y/z³).
+  FieldElement x, y, z;
+};
+
+// kScalarBytes is the number of bytes needed to represent an element of the
+// P224 field.
+static const size_t kScalarBytes = 28;
+
+// ScalarMult computes *out = in*scalar where scalar is a 28-byte, big-endian
+// number.
+void CRYPTO_EXPORT ScalarMult(const Point& in,
+                              const uint8_t* scalar,
+                              Point* out);
+
+// ScalarBaseMult computes *out = g*scalar where g is the base point of the
+// curve and scalar is a 28-byte, big-endian number.
+void CRYPTO_EXPORT ScalarBaseMult(const uint8_t* scalar, Point* out);
+
+// Add computes *out = a+b.
+void CRYPTO_EXPORT Add(const Point& a, const Point& b, Point* out);
+
+// Negate calculates out = -a;
+void CRYPTO_EXPORT Negate(const Point& a, Point* out);
+
+}  // namespace p224
+
+}  // namespace crypto
+
+#endif  // CRYPTO_P224_H_
diff --git a/libchrome/crypto/p224_spake.cc b/libchrome/crypto/p224_spake.cc
new file mode 100644
index 0000000..1574105
--- /dev/null
+++ b/libchrome/crypto/p224_spake.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.
+
+// This code implements SPAKE2, a variant of EKE:
+//  http://www.di.ens.fr/~pointche/pub.php?reference=AbPo04
+
+#include <crypto/p224_spake.h>
+
+#include <algorithm>
+
+#include <base/logging.h>
+#include <crypto/p224.h>
+#include <crypto/random.h>
+#include <crypto/secure_util.h>
+
+namespace {
+
+// The following two points (M and N in the protocol) are verifiable random
+// points on the curve and can be generated with the following code:
+
+// #include <stdint.h>
+// #include <stdio.h>
+// #include <string.h>
+//
+// #include <openssl/ec.h>
+// #include <openssl/obj_mac.h>
+// #include <openssl/sha.h>
+//
+// static const char kSeed1[] = "P224 point generation seed (M)";
+// static const char kSeed2[] = "P224 point generation seed (N)";
+//
+// void find_seed(const char* seed) {
+//   SHA256_CTX sha256;
+//   uint8_t digest[SHA256_DIGEST_LENGTH];
+//
+//   SHA256_Init(&sha256);
+//   SHA256_Update(&sha256, seed, strlen(seed));
+//   SHA256_Final(digest, &sha256);
+//
+//   BIGNUM x, y;
+//   EC_GROUP* p224 = EC_GROUP_new_by_curve_name(NID_secp224r1);
+//   EC_POINT* p = EC_POINT_new(p224);
+//
+//   for (unsigned i = 0;; i++) {
+//     BN_init(&x);
+//     BN_bin2bn(digest, 28, &x);
+//
+//     if (EC_POINT_set_compressed_coordinates_GFp(
+//             p224, p, &x, digest[28] & 1, NULL)) {
+//       BN_init(&y);
+//       EC_POINT_get_affine_coordinates_GFp(p224, p, &x, &y, NULL);
+//       char* x_str = BN_bn2hex(&x);
+//       char* y_str = BN_bn2hex(&y);
+//       printf("Found after %u iterations:\n%s\n%s\n", i, x_str, y_str);
+//       OPENSSL_free(x_str);
+//       OPENSSL_free(y_str);
+//       BN_free(&x);
+//       BN_free(&y);
+//       break;
+//     }
+//
+//     SHA256_Init(&sha256);
+//     SHA256_Update(&sha256, digest, sizeof(digest));
+//     SHA256_Final(digest, &sha256);
+//
+//     BN_free(&x);
+//   }
+//
+//   EC_POINT_free(p);
+//   EC_GROUP_free(p224);
+// }
+//
+// int main() {
+//   find_seed(kSeed1);
+//   find_seed(kSeed2);
+//   return 0;
+// }
+
+const crypto::p224::Point kM = {
+  {174237515, 77186811, 235213682, 33849492,
+   33188520, 48266885, 177021753, 81038478},
+  {104523827, 245682244, 266509668, 236196369,
+   28372046, 145351378, 198520366, 113345994},
+  {1, 0, 0, 0, 0, 0, 0, 0},
+};
+
+const crypto::p224::Point kN = {
+  {136176322, 263523628, 251628795, 229292285,
+   5034302, 185981975, 171998428, 11653062},
+  {197567436, 51226044, 60372156, 175772188,
+   42075930, 8083165, 160827401, 65097570},
+  {1, 0, 0, 0, 0, 0, 0, 0},
+};
+
+}  // anonymous namespace
+
+namespace crypto {
+
+P224EncryptedKeyExchange::P224EncryptedKeyExchange(
+    PeerType peer_type, const base::StringPiece& password)
+    : state_(kStateInitial),
+      is_server_(peer_type == kPeerTypeServer) {
+  memset(&x_, 0, sizeof(x_));
+  memset(&expected_authenticator_, 0, sizeof(expected_authenticator_));
+
+  // x_ is a random scalar.
+  RandBytes(x_, sizeof(x_));
+
+  // Calculate |password| hash to get SPAKE password value.
+  SHA256HashString(std::string(password.data(), password.length()),
+                   pw_, sizeof(pw_));
+
+  Init();
+}
+
+void P224EncryptedKeyExchange::Init() {
+  // X = g**x_
+  p224::Point X;
+  p224::ScalarBaseMult(x_, &X);
+
+  // The client masks the Diffie-Hellman value, X, by adding M**pw and the
+  // server uses N**pw.
+  p224::Point MNpw;
+  p224::ScalarMult(is_server_ ? kN : kM, pw_, &MNpw);
+
+  // X* = X + (N|M)**pw
+  p224::Point Xstar;
+  p224::Add(X, MNpw, &Xstar);
+
+  next_message_ = Xstar.ToString();
+}
+
+const std::string& P224EncryptedKeyExchange::GetNextMessage() {
+  if (state_ == kStateInitial) {
+    state_ = kStateRecvDH;
+    return next_message_;
+  } else if (state_ == kStateSendHash) {
+    state_ = kStateRecvHash;
+    return next_message_;
+  }
+
+  LOG(FATAL) << "P224EncryptedKeyExchange::GetNextMessage called in"
+                " bad state " << state_;
+  next_message_ = "";
+  return next_message_;
+}
+
+P224EncryptedKeyExchange::Result P224EncryptedKeyExchange::ProcessMessage(
+    const base::StringPiece& message) {
+  if (state_ == kStateRecvHash) {
+    // This is the final state of the protocol: we are reading the peer's
+    // authentication hash and checking that it matches the one that we expect.
+    if (message.size() != sizeof(expected_authenticator_)) {
+      error_ = "peer's hash had an incorrect size";
+      return kResultFailed;
+    }
+    if (!SecureMemEqual(message.data(), expected_authenticator_,
+                        message.size())) {
+      error_ = "peer's hash had incorrect value";
+      return kResultFailed;
+    }
+    state_ = kStateDone;
+    return kResultSuccess;
+  }
+
+  if (state_ != kStateRecvDH) {
+    LOG(FATAL) << "P224EncryptedKeyExchange::ProcessMessage called in"
+                  " bad state " << state_;
+    error_ = "internal error";
+    return kResultFailed;
+  }
+
+  // Y* is the other party's masked, Diffie-Hellman value.
+  p224::Point Ystar;
+  if (!Ystar.SetFromString(message)) {
+    error_ = "failed to parse peer's masked Diffie-Hellman value";
+    return kResultFailed;
+  }
+
+  // We calculate the mask value: (N|M)**pw
+  p224::Point MNpw, minus_MNpw, Y, k;
+  p224::ScalarMult(is_server_ ? kM : kN, pw_, &MNpw);
+  p224::Negate(MNpw, &minus_MNpw);
+
+  // Y = Y* - (N|M)**pw
+  p224::Add(Ystar, minus_MNpw, &Y);
+
+  // K = Y**x_
+  p224::ScalarMult(Y, x_, &k);
+
+  // If everything worked out, then K is the same for both parties.
+  key_ = k.ToString();
+
+  std::string client_masked_dh, server_masked_dh;
+  if (is_server_) {
+    client_masked_dh = message.as_string();
+    server_masked_dh = next_message_;
+  } else {
+    client_masked_dh = next_message_;
+    server_masked_dh = message.as_string();
+  }
+
+  // Now we calculate the hashes that each side will use to prove to the other
+  // that they derived the correct value for K.
+  uint8_t client_hash[kSHA256Length], server_hash[kSHA256Length];
+  CalculateHash(kPeerTypeClient, client_masked_dh, server_masked_dh, key_,
+                client_hash);
+  CalculateHash(kPeerTypeServer, client_masked_dh, server_masked_dh, key_,
+                server_hash);
+
+  const uint8_t* my_hash = is_server_ ? server_hash : client_hash;
+  const uint8_t* their_hash = is_server_ ? client_hash : server_hash;
+
+  next_message_ =
+      std::string(reinterpret_cast<const char*>(my_hash), kSHA256Length);
+  memcpy(expected_authenticator_, their_hash, kSHA256Length);
+  state_ = kStateSendHash;
+  return kResultPending;
+}
+
+void P224EncryptedKeyExchange::CalculateHash(
+    PeerType peer_type,
+    const std::string& client_masked_dh,
+    const std::string& server_masked_dh,
+    const std::string& k,
+    uint8_t* out_digest) {
+  std::string hash_contents;
+
+  if (peer_type == kPeerTypeServer) {
+    hash_contents = "server";
+  } else {
+    hash_contents = "client";
+  }
+
+  hash_contents += client_masked_dh;
+  hash_contents += server_masked_dh;
+  hash_contents +=
+      std::string(reinterpret_cast<const char *>(pw_), sizeof(pw_));
+  hash_contents += k;
+
+  SHA256HashString(hash_contents, out_digest, kSHA256Length);
+}
+
+const std::string& P224EncryptedKeyExchange::error() const {
+  return error_;
+}
+
+const std::string& P224EncryptedKeyExchange::GetKey() const {
+  DCHECK_EQ(state_, kStateDone);
+  return GetUnverifiedKey();
+}
+
+const std::string& P224EncryptedKeyExchange::GetUnverifiedKey() const {
+  // Key is already final when state is kStateSendHash. Subsequent states are
+  // used only for verification of the key. Some users may combine verification
+  // with sending verifiable data instead of |expected_authenticator_|.
+  DCHECK_GE(state_, kStateSendHash);
+  return key_;
+}
+
+void P224EncryptedKeyExchange::SetXForTesting(const std::string& x) {
+  memset(&x_, 0, sizeof(x_));
+  memcpy(&x_, x.data(), std::min(x.size(), sizeof(x_)));
+  Init();
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/p224_spake.h b/libchrome/crypto/p224_spake.h
new file mode 100644
index 0000000..f9a44e7
--- /dev/null
+++ b/libchrome/crypto/p224_spake.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_P224_SPAKE_H_
+#define CRYPTO_P224_SPAKE_H_
+
+#include <crypto/p224.h>
+#include <crypto/sha2.h>
+#include <stdint.h>
+
+#include "base/gtest_prod_util.h"
+#include "base/strings/string_piece.h"
+
+namespace crypto {
+
+// P224EncryptedKeyExchange implements SPAKE2, a variant of Encrypted
+// Key Exchange. It allows two parties that have a secret common
+// password to establish a common secure key by exchanging messages
+// over an insecure channel without disclosing the password.
+//
+// The password can be low entropy as authenticating with an attacker only
+// gives the attacker a one-shot password oracle. No other information about
+// the password is leaked. (However, you must be sure to limit the number of
+// permitted authentication attempts otherwise they get many one-shot oracles.)
+//
+// The protocol requires several RTTs (actually two, but you shouldn't assume
+// that.) To use the object, call GetNextMessage() and pass that message to the
+// peer. Get a message from the peer and feed it into ProcessMessage. Then
+// examine the return value of ProcessMessage:
+//   kResultPending: Another round is required. Call GetNextMessage and repeat.
+//   kResultFailed: The authentication has failed. You can get a human readable
+//       error message by calling error().
+//   kResultSuccess: The authentication was successful.
+//
+// In each exchange, each peer always sends a message.
+class CRYPTO_EXPORT P224EncryptedKeyExchange {
+ public:
+  enum Result {
+    kResultPending,
+    kResultFailed,
+    kResultSuccess,
+  };
+
+  // PeerType's values are named client and server due to convention. But
+  // they could be called "A" and "B" as far as the protocol is concerned so
+  // long as the two parties don't both get the same label.
+  enum PeerType {
+    kPeerTypeClient,
+    kPeerTypeServer,
+  };
+
+  // peer_type: the type of the local authentication party.
+  // password: secret session password. Both parties to the
+  //     authentication must pass the same value. For the case of a
+  //     TLS connection, see RFC 5705.
+  P224EncryptedKeyExchange(PeerType peer_type,
+                           const base::StringPiece& password);
+
+  // GetNextMessage returns a byte string which must be passed to the other
+  // party in the authentication.
+  const std::string& GetNextMessage();
+
+  // ProcessMessage processes a message which must have been generated by a
+  // call to GetNextMessage() by the other party.
+  Result ProcessMessage(const base::StringPiece& message);
+
+  // In the event that ProcessMessage() returns kResultFailed, error will
+  // return a human readable error message.
+  const std::string& error() const;
+
+  // The key established as result of the key exchange. Must be called
+  // at then end after ProcessMessage() returns kResultSuccess.
+  const std::string& GetKey() const;
+
+  // The key established as result of the key exchange. Can be called after
+  // the first ProcessMessage()
+  const std::string& GetUnverifiedKey() const;
+
+ private:
+  // The authentication state machine is very simple and each party proceeds
+  // through each of these states, in order.
+  enum State {
+    kStateInitial,
+    kStateRecvDH,
+    kStateSendHash,
+    kStateRecvHash,
+    kStateDone,
+  };
+
+  FRIEND_TEST_ALL_PREFIXES(MutualAuth, ExpectedValues);
+
+  void Init();
+
+  // Sets internal random scalar. Should be used by tests only.
+  void SetXForTesting(const std::string& x);
+
+  State state_;
+  const bool is_server_;
+  // next_message_ contains a value for GetNextMessage() to return.
+  std::string next_message_;
+  std::string error_;
+
+  // CalculateHash computes the verification hash for the given peer and writes
+  // |kSHA256Length| bytes at |out_digest|.
+  void CalculateHash(PeerType peer_type,
+                     const std::string& client_masked_dh,
+                     const std::string& server_masked_dh,
+                     const std::string& k,
+                     uint8_t* out_digest);
+
+  // x_ is the secret Diffie-Hellman exponent (see paper referenced in .cc
+  // file).
+  uint8_t x_[p224::kScalarBytes];
+  // pw_ is SHA256(P(password), P(session))[:28] where P() prepends a uint32_t,
+  // big-endian length prefix (see paper referenced in .cc file).
+  uint8_t pw_[p224::kScalarBytes];
+  // expected_authenticator_ is used to store the hash value expected from the
+  // other party.
+  uint8_t expected_authenticator_[kSHA256Length];
+
+  std::string key_;
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_P224_SPAKE_H_
diff --git a/libchrome/crypto/p224_spake_unittest.cc b/libchrome/crypto/p224_spake_unittest.cc
new file mode 100644
index 0000000..3bca430
--- /dev/null
+++ b/libchrome/crypto/p224_spake_unittest.cc
@@ -0,0 +1,177 @@
+// 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 "crypto/p224_spake.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+namespace {
+
+std::string HexEncodeString(const std::string& binary_data) {
+  return base::HexEncode(binary_data.c_str(), binary_data.size());
+}
+
+bool RunExchange(P224EncryptedKeyExchange* client,
+                 P224EncryptedKeyExchange* server,
+                 bool is_password_same) {
+  for (;;) {
+    std::string client_message, server_message;
+    client_message = client->GetNextMessage();
+    server_message = server->GetNextMessage();
+
+    P224EncryptedKeyExchange::Result client_result, server_result;
+    client_result = client->ProcessMessage(server_message);
+    server_result = server->ProcessMessage(client_message);
+
+    // Check that we never hit the case where only one succeeds.
+    EXPECT_EQ(client_result == P224EncryptedKeyExchange::kResultSuccess,
+              server_result == P224EncryptedKeyExchange::kResultSuccess);
+
+    if (client_result == P224EncryptedKeyExchange::kResultFailed ||
+        server_result == P224EncryptedKeyExchange::kResultFailed) {
+      return false;
+    }
+
+    EXPECT_EQ(is_password_same,
+              client->GetUnverifiedKey() == server->GetUnverifiedKey());
+
+    if (client_result == P224EncryptedKeyExchange::kResultSuccess &&
+        server_result == P224EncryptedKeyExchange::kResultSuccess) {
+      return true;
+    }
+
+    EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, client_result);
+    EXPECT_EQ(P224EncryptedKeyExchange::kResultPending, server_result);
+  }
+}
+
+const char kPassword[] = "foo";
+
+}  // namespace
+
+TEST(MutualAuth, CorrectAuth) {
+  P224EncryptedKeyExchange client(
+      P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
+  P224EncryptedKeyExchange server(
+      P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
+
+  EXPECT_TRUE(RunExchange(&client, &server, true));
+  EXPECT_EQ(client.GetKey(), server.GetKey());
+}
+
+TEST(MutualAuth, IncorrectPassword) {
+  P224EncryptedKeyExchange client(
+      P224EncryptedKeyExchange::kPeerTypeClient,
+      kPassword);
+  P224EncryptedKeyExchange server(
+      P224EncryptedKeyExchange::kPeerTypeServer,
+      "wrongpassword");
+
+  EXPECT_FALSE(RunExchange(&client, &server, false));
+}
+
+TEST(MutualAuth, ExpectedValues) {
+  P224EncryptedKeyExchange client(P224EncryptedKeyExchange::kPeerTypeClient,
+                                  kPassword);
+  client.SetXForTesting("Client x");
+  P224EncryptedKeyExchange server(P224EncryptedKeyExchange::kPeerTypeServer,
+                                  kPassword);
+  server.SetXForTesting("Server x");
+
+  std::string client_message = client.GetNextMessage();
+  EXPECT_EQ(
+      "3508EF7DECC8AB9F9C439FBB0154288BBECC0A82E8448F4CF29554EB"
+      "BE9D486686226255EAD1D077C635B1A41F46AC91D7F7F32CED9EC3E0",
+      HexEncodeString(client_message));
+
+  std::string server_message = server.GetNextMessage();
+  EXPECT_EQ(
+      "A3088C18B75D2C2B107105661AEC85424777475EB29F1DDFB8C14AFB"
+      "F1603D0DF38413A00F420ACF2059E7997C935F5A957A193D09A2B584",
+      HexEncodeString(server_message));
+
+  EXPECT_EQ(P224EncryptedKeyExchange::kResultPending,
+            client.ProcessMessage(server_message));
+  EXPECT_EQ(P224EncryptedKeyExchange::kResultPending,
+            server.ProcessMessage(client_message));
+
+  EXPECT_EQ(client.GetUnverifiedKey(), server.GetUnverifiedKey());
+  // Must stay the same. External implementations should be able to pair with.
+  EXPECT_EQ(
+      "CE7CCFC435CDA4F01EC8826788B1F8B82EF7D550A34696B371096E64"
+      "C487D4FE193F7D1A6FF6820BC7F807796BA3889E8F999BBDEFC32FFA",
+      HexEncodeString(server.GetUnverifiedKey()));
+
+  EXPECT_TRUE(RunExchange(&client, &server, true));
+  EXPECT_EQ(client.GetKey(), server.GetKey());
+}
+
+TEST(MutualAuth, Fuzz) {
+  static const unsigned kIterations = 40;
+
+  for (unsigned i = 0; i < kIterations; i++) {
+    P224EncryptedKeyExchange client(
+        P224EncryptedKeyExchange::kPeerTypeClient, kPassword);
+    P224EncryptedKeyExchange server(
+        P224EncryptedKeyExchange::kPeerTypeServer, kPassword);
+
+    // We'll only be testing small values of i, but we don't want that to bias
+    // the test coverage. So we disperse the value of i by multiplying by the
+    // FNV, 32-bit prime, producing a poor-man's PRNG.
+    const uint32_t rand = i * 16777619;
+
+    for (unsigned round = 0;; round++) {
+      std::string client_message, server_message;
+      client_message = client.GetNextMessage();
+      server_message = server.GetNextMessage();
+
+      if ((rand & 1) == round) {
+        const bool server_or_client = rand & 2;
+        std::string* m = server_or_client ? &server_message : &client_message;
+        if (rand & 4) {
+          // Truncate
+          *m = m->substr(0, (i >> 3) % m->size());
+        } else {
+          // Corrupt
+          const size_t bits = m->size() * 8;
+          const size_t bit_to_corrupt = (rand >> 3) % bits;
+          const_cast<char*>(m->data())[bit_to_corrupt / 8] ^=
+              1 << (bit_to_corrupt % 8);
+        }
+      }
+
+      P224EncryptedKeyExchange::Result client_result, server_result;
+      client_result = client.ProcessMessage(server_message);
+      server_result = server.ProcessMessage(client_message);
+
+      // If we have corrupted anything, we expect the authentication to fail,
+      // although one side can succeed if we happen to corrupt the second round
+      // message to the other.
+      ASSERT_FALSE(
+          client_result == P224EncryptedKeyExchange::kResultSuccess &&
+          server_result == P224EncryptedKeyExchange::kResultSuccess);
+
+      if (client_result == P224EncryptedKeyExchange::kResultFailed ||
+          server_result == P224EncryptedKeyExchange::kResultFailed) {
+        break;
+      }
+
+      ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
+                client_result);
+      ASSERT_EQ(P224EncryptedKeyExchange::kResultPending,
+                server_result);
+    }
+  }
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/p224_unittest.cc b/libchrome/crypto/p224_unittest.cc
new file mode 100644
index 0000000..faa08eb
--- /dev/null
+++ b/libchrome/crypto/p224_unittest.cc
@@ -0,0 +1,825 @@
+// Copyright (c) 2012 The Chromium Authors. 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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "crypto/p224.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace crypto {
+
+using p224::Point;
+
+// kBasePointExternal is the P224 base point in external representation.
+static const uint8_t kBasePointExternal[56] = {
+    0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9,
+    0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
+    0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb,
+    0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64,
+    0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34,
+};
+
+// TestVector represents a test of scalar multiplication of the base point.
+// |scalar| is a big-endian scalar and |affine| is the external representation
+// of g*scalar.
+struct TestVector {
+  uint8_t scalar[28];
+  uint8_t affine[28 * 2];
+};
+
+static const int kNumNISTTestVectors = 52;
+
+// kNISTTestVectors are the NIST test vectors for P224.
+static const TestVector kNISTTestVectors[kNumNISTTestVectors] = {
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x01},
+    {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f,
+     0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3,
+     0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
+     0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88,
+     0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6,
+     0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64,
+     0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x02, },
+
+    {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67,
+     0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88,
+     0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd,
+     0x1a, 0x70, 0x4f, 0xa6, 0x1c, 0x2b, 0x76, 0xa7,
+     0xbc, 0x25, 0xe7, 0x70, 0x2a, 0x70, 0x4f, 0xa9,
+     0x86, 0x89, 0x28, 0x49, 0xfc, 0xa6, 0x29, 0x48,
+     0x7a, 0xcf, 0x37, 0x09, 0xd2, 0xe4, 0xe8, 0xbb,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x03, },
+    {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3,
+     0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc,
+     0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08,
+     0xfd, 0x89, 0x6d, 0x04, 0xa3, 0xf7, 0xf0, 0x3c,
+     0xad, 0xd0, 0xbe, 0x44, 0x4c, 0x0a, 0xa5, 0x68,
+     0x30, 0x13, 0x0d, 0xdf, 0x77, 0xd3, 0x17, 0x34,
+     0x4e, 0x1a, 0xf3, 0x59, 0x19, 0x81, 0xa9, 0x25,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x04, },
+    {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45,
+     0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02,
+     0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e,
+     0x40, 0x44, 0x73, 0x01, 0x04, 0x82, 0x58, 0x0a,
+     0x0e, 0xc5, 0xbc, 0x47, 0xe8, 0x8b, 0xc8, 0xc3,
+     0x78, 0x63, 0x2c, 0xd1, 0x96, 0xcb, 0x3f, 0xa0,
+     0x58, 0xa7, 0x11, 0x4e, 0xb0, 0x30, 0x54, 0xc9,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x05, },
+    {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07,
+     0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90,
+     0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75,
+     0x26, 0xf0, 0x11, 0xaa, 0x27, 0xe8, 0xbf, 0xf1,
+     0x74, 0x56, 0x35, 0xec, 0x5b, 0xa0, 0xc9, 0xf1,
+     0xc2, 0xed, 0xe1, 0x54, 0x14, 0xc6, 0x50, 0x7d,
+     0x29, 0xff, 0xe3, 0x7e, 0x79, 0x0a, 0x07, 0x9b,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x06, },
+    {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f,
+     0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d,
+     0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c,
+     0x57, 0x11, 0x24, 0x08, 0x89, 0xfa, 0xf0, 0xcc,
+     0xb7, 0x50, 0xd9, 0x9b, 0x55, 0x3c, 0x57, 0x4f,
+     0xad, 0x7e, 0xcf, 0xb0, 0x43, 0x85, 0x86, 0xeb,
+     0x39, 0x52, 0xaf, 0x5b, 0x4b, 0x15, 0x3c, 0x7e,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x07, },
+    {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5,
+     0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23,
+     0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24,
+     0xa0, 0x3c, 0x3e, 0x28, 0x0f, 0x3a, 0x30, 0x08,
+     0x54, 0x97, 0xf2, 0xf6, 0x11, 0xee, 0x25, 0x17,
+     0xb1, 0x63, 0xef, 0x8c, 0x53, 0xb7, 0x15, 0xd1,
+     0x8b, 0xb4, 0xe4, 0x80, 0x8d, 0x02, 0xb9, 0x63,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x08, },
+    {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31,
+     0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0,
+     0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b,
+     0x55, 0x57, 0x15, 0x50, 0x04, 0x6d, 0xcd, 0x3e,
+     0xa5, 0xc4, 0x38, 0x98, 0xc5, 0xc5, 0xfc, 0x4f,
+     0xda, 0xc7, 0xdb, 0x39, 0xc2, 0xf0, 0x2e, 0xbe,
+     0xe4, 0xe3, 0x54, 0x1d, 0x1e, 0x78, 0x04, 0x7a,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x09, },
+    {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e,
+     0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38,
+     0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36,
+     0xed, 0x15, 0xf7, 0x8d, 0x37, 0x17, 0x32, 0xe4,
+     0xf4, 0x1b, 0xf4, 0xf7, 0x88, 0x30, 0x35, 0xe6,
+     0xa7, 0x9f, 0xce, 0xdc, 0x0e, 0x19, 0x6e, 0xb0,
+     0x7b, 0x48, 0x17, 0x16, 0x97, 0x51, 0x74, 0x63,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x0a, },
+    {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb,
+     0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38,
+     0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7,
+     0xbe, 0xe2, 0xc0, 0xfd, 0x39, 0xbb, 0x30, 0xea,
+     0xb3, 0x37, 0xe0, 0xa5, 0x21, 0xb6, 0xcb, 0xa1,
+     0xab, 0xe4, 0xb2, 0xb3, 0xa3, 0xe5, 0x24, 0xc1,
+     0x4a, 0x3f, 0xe3, 0xeb, 0x11, 0x6b, 0x65, 0x5f,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x0b, },
+    {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f,
+     0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50,
+     0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16,
+     0x44, 0x8e, 0x50, 0x7c, 0x20, 0xb5, 0x10, 0x00,
+     0x40, 0x92, 0xe9, 0x66, 0x36, 0xcf, 0xb7, 0xe3,
+     0x2e, 0xfd, 0xed, 0x82, 0x65, 0xc2, 0x66, 0xdf,
+     0xb7, 0x54, 0xfa, 0x6d, 0x64, 0x91, 0xa6, 0xda,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x0c, },
+    {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b,
+     0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43,
+     0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3,
+     0x04, 0x4f, 0x4f, 0x7a, 0x20, 0x7d, 0xdd, 0xf0,
+     0x38, 0x5b, 0xfd, 0xea, 0xb6, 0xe9, 0xac, 0xda,
+     0x8d, 0xa0, 0x6b, 0x3b, 0xbe, 0xf2, 0x24, 0xa9,
+     0x3a, 0xb1, 0xe9, 0xe0, 0x36, 0x10, 0x9d, 0x13,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x0d, },
+    {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28,
+     0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42,
+     0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98,
+     0x1f, 0xcf, 0xae, 0xca, 0x25, 0x28, 0x19, 0xf7,
+     0x1c, 0x7f, 0xb7, 0xfb, 0xcb, 0x15, 0x9b, 0xe3,
+     0x37, 0xd3, 0x7d, 0x33, 0x36, 0xd7, 0xfe, 0xb9,
+     0x63, 0x72, 0x4f, 0xdf, 0xb0, 0xec, 0xb7, 0x67,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x0e, },
+    {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60,
+     0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2,
+     0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2,
+     0xce, 0x01, 0xe9, 0xfa, 0xd5, 0x81, 0x4c, 0xd7,
+     0x24, 0x19, 0x9c, 0x4a, 0x5b, 0x97, 0x4a, 0x43,
+     0x68, 0x5f, 0xbf, 0x5b, 0x8b, 0xac, 0x69, 0x45,
+     0x9c, 0x94, 0x69, 0xbc, 0x8f, 0x23, 0xcc, 0xaf,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x0f, },
+    {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2,
+     0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29,
+     0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e,
+     0x21, 0x91, 0x6b, 0xf9, 0x97, 0x9a, 0x5f, 0x47,
+     0x59, 0xf8, 0x0f, 0x4f, 0xb4, 0xec, 0x2e, 0x34,
+     0xf5, 0x56, 0x6d, 0x59, 0x56, 0x80, 0xa1, 0x17,
+     0x35, 0xe7, 0xb6, 0x10, 0x46, 0x12, 0x79, 0x89,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x10, },
+    {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24,
+     0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c,
+     0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5,
+     0x90, 0xc4, 0xc6, 0x6d, 0x33, 0x99, 0xd4, 0x64,
+     0x34, 0x59, 0x06, 0xb1, 0x1b, 0x00, 0xe3, 0x63,
+     0xef, 0x42, 0x92, 0x21, 0xf2, 0xec, 0x72, 0x0d,
+     0x2f, 0x66, 0x5d, 0x7d, 0xea, 0xd5, 0xb4, 0x82,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x11, },
+    {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88,
+     0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20,
+     0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c,
+     0x48, 0x44, 0x03, 0xbc, 0xff, 0x14, 0x9e, 0xfa,
+     0x66, 0x06, 0xa6, 0xbd, 0x20, 0xef, 0x7d, 0x1b,
+     0x06, 0xbd, 0x92, 0xf6, 0x90, 0x46, 0x39, 0xdc,
+     0xe5, 0x17, 0x4d, 0xb6, 0xcc, 0x55, 0x4a, 0x26,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x12, },
+    {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05,
+     0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea,
+     0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74,
+     0x62, 0x26, 0xe4, 0xcc, 0xea, 0x98, 0xd6, 0x0e,
+     0x5f, 0xfc, 0x9b, 0x8f, 0xcf, 0x99, 0x9f, 0xab,
+     0x1d, 0xf7, 0xe7, 0xef, 0x70, 0x84, 0xf2, 0x0d,
+     0xdb, 0x61, 0xbb, 0x04, 0x5a, 0x6c, 0xe0, 0x02,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x13, },
+    {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01,
+     0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc,
+     0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb,
+     0xc6, 0xca, 0xe8, 0x3c, 0xdc, 0xf1, 0xf6, 0xc3,
+     0xdb, 0x09, 0xc7, 0x0a, 0xcc, 0x25, 0x39, 0x1d,
+     0x49, 0x2f, 0xe2, 0x5b, 0x4a, 0x18, 0x0b, 0xab,
+     0xd6, 0xce, 0xa3, 0x56, 0xc0, 0x47, 0x19, 0xcd,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x14, },
+    {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a,
+     0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf,
+     0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee,
+     0xfe, 0x78, 0x24, 0x55, 0x0d, 0x5d, 0x71, 0x10,
+     0x27, 0x4c, 0xba, 0x7c, 0xde, 0xe9, 0x0e, 0x1a,
+     0x8b, 0x0d, 0x39, 0x4c, 0x37, 0x6a, 0x55, 0x73,
+     0xdb, 0x6b, 0xe0, 0xbf, 0x27, 0x47, 0xf5, 0x30,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x01, 0x8e, 0xbb, 0xb9,
+     0x5e, 0xed, 0x0e, 0x13, },
+    {0x61, 0xf0, 0x77, 0xc6, 0xf6, 0x2e, 0xd8, 0x02,
+     0xda, 0xd7, 0xc2, 0xf3, 0x8f, 0x5c, 0x67, 0xf2,
+     0xcc, 0x45, 0x36, 0x01, 0xe6, 0x1b, 0xd0, 0x76,
+     0xbb, 0x46, 0x17, 0x9e, 0x22, 0x72, 0xf9, 0xe9,
+     0xf5, 0x93, 0x3e, 0x70, 0x38, 0x8e, 0xe6, 0x52,
+     0x51, 0x34, 0x43, 0xb5, 0xe2, 0x89, 0xdd, 0x13,
+     0x5d, 0xcc, 0x0d, 0x02, 0x99, 0xb2, 0x25, 0xe4,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x9d, 0x89,
+     0x3d, 0x4c, 0xdd, 0x74, 0x72, 0x46, 0xcd, 0xca,
+     0x43, 0x59, 0x0e, 0x13, },
+    {0x02, 0x98, 0x95, 0xf0, 0xaf, 0x49, 0x6b, 0xfc,
+     0x62, 0xb6, 0xef, 0x8d, 0x8a, 0x65, 0xc8, 0x8c,
+     0x61, 0x39, 0x49, 0xb0, 0x36, 0x68, 0xaa, 0xb4,
+     0xf0, 0x42, 0x9e, 0x35, 0x3e, 0xa6, 0xe5, 0x3f,
+     0x9a, 0x84, 0x1f, 0x20, 0x19, 0xec, 0x24, 0xbd,
+     0xe1, 0xa7, 0x56, 0x77, 0xaa, 0x9b, 0x59, 0x02,
+     0xe6, 0x10, 0x81, 0xc0, 0x10, 0x64, 0xde, 0x93,
+    },
+  },
+  {
+    {0x41, 0xff, 0xc1, 0xff, 0xff, 0xfe, 0x01, 0xff,
+     0xfc, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x07, 0xc0,
+     0x01, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xf0, 0x7f,
+     0xfe, 0x00, 0x07, 0xc0, },
+    {0xab, 0x68, 0x99, 0x30, 0xbc, 0xae, 0x4a, 0x4a,
+     0xa5, 0xf5, 0xcb, 0x08, 0x5e, 0x82, 0x3e, 0x8a,
+     0xe3, 0x0f, 0xd3, 0x65, 0xeb, 0x1d, 0xa4, 0xab,
+     0xa9, 0xcf, 0x03, 0x79, 0x33, 0x45, 0xa1, 0x21,
+     0xbb, 0xd2, 0x33, 0x54, 0x8a, 0xf0, 0xd2, 0x10,
+     0x65, 0x4e, 0xb4, 0x0b, 0xab, 0x78, 0x8a, 0x03,
+     0x66, 0x64, 0x19, 0xbe, 0x6f, 0xbd, 0x34, 0xe7,
+    },
+  },
+  {
+    {0x7f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xc0, 0x03,
+     0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x00, 0x00,
+     0x00, 0x00, 0x07, 0x00, 0x00, 0x10, 0x00, 0x00,
+     0x00, 0x0e, 0x00, 0xff, },
+    {0xbd, 0xb6, 0xa8, 0x81, 0x7c, 0x1f, 0x89, 0xda,
+     0x1c, 0x2f, 0x3d, 0xd8, 0xe9, 0x7f, 0xeb, 0x44,
+     0x94, 0xf2, 0xed, 0x30, 0x2a, 0x4c, 0xe2, 0xbc,
+     0x7f, 0x5f, 0x40, 0x25, 0x4c, 0x70, 0x20, 0xd5,
+     0x7c, 0x00, 0x41, 0x18, 0x89, 0x46, 0x2d, 0x77,
+     0xa5, 0x43, 0x8b, 0xb4, 0xe9, 0x7d, 0x17, 0x77,
+     0x00, 0xbf, 0x72, 0x43, 0xa0, 0x7f, 0x16, 0x80,
+    },
+  },
+  {
+    {0x7f, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00,
+     0xff, 0xff, 0xf0, 0x1f, 0xff, 0xf8, 0xff, 0xff,
+     0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
+     0x00, 0x0f, 0xff, 0xff, },
+    {0xd5, 0x8b, 0x61, 0xaa, 0x41, 0xc3, 0x2d, 0xd5,
+     0xeb, 0xa4, 0x62, 0x64, 0x7d, 0xba, 0x75, 0xc5,
+     0xd6, 0x7c, 0x83, 0x60, 0x6c, 0x0a, 0xf2, 0xbd,
+     0x92, 0x84, 0x46, 0xa9, 0xd2, 0x4b, 0xa6, 0xa8,
+     0x37, 0xbe, 0x04, 0x60, 0xdd, 0x10, 0x7a, 0xe7,
+     0x77, 0x25, 0x69, 0x6d, 0x21, 0x14, 0x46, 0xc5,
+     0x60, 0x9b, 0x45, 0x95, 0x97, 0x6b, 0x16, 0xbd,
+    },
+  },
+  {
+    {0x7f, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xfe, 0x3f,
+     0xff, 0xfc, 0x10, 0x00, 0x00, 0x20, 0x00, 0x3f,
+     0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
+     0x3f, 0xff, 0xff, 0xff, },
+    {0xdc, 0x9f, 0xa7, 0x79, 0x78, 0xa0, 0x05, 0x51,
+     0x09, 0x80, 0xe9, 0x29, 0xa1, 0x48, 0x5f, 0x63,
+     0x71, 0x6d, 0xf6, 0x95, 0xd7, 0xa0, 0xc1, 0x8b,
+     0xb5, 0x18, 0xdf, 0x03, 0xed, 0xe2, 0xb0, 0x16,
+     0xf2, 0xdd, 0xff, 0xc2, 0xa8, 0xc0, 0x15, 0xb1,
+     0x34, 0x92, 0x82, 0x75, 0xce, 0x09, 0xe5, 0x66,
+     0x1b, 0x7a, 0xb1, 0x4c, 0xe0, 0xd1, 0xd4, 0x03,
+    },
+  },
+  {
+    {0x70, 0x01, 0xf0, 0x00, 0x1c, 0x00, 0x01, 0xc0,
+     0x00, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x00, 0x00,
+     0x1f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xc0, 0x00,
+     0x00, 0x01, 0xfc, 0x00, },
+    {0x49, 0x9d, 0x8b, 0x28, 0x29, 0xcf, 0xb8, 0x79,
+     0xc9, 0x01, 0xf7, 0xd8, 0x5d, 0x35, 0x70, 0x45,
+     0xed, 0xab, 0x55, 0x02, 0x88, 0x24, 0xd0, 0xf0,
+     0x5b, 0xa2, 0x79, 0xba, 0xbf, 0x92, 0x95, 0x37,
+     0xb0, 0x6e, 0x40, 0x15, 0x91, 0x96, 0x39, 0xd9,
+     0x4f, 0x57, 0x83, 0x8f, 0xa3, 0x3f, 0xc3, 0xd9,
+     0x52, 0x59, 0x8d, 0xcd, 0xbb, 0x44, 0xd6, 0x38,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00,
+     0x00, 0xff, 0xf0, 0x30, 0x00, 0x1f, 0x00, 0x00,
+     0xff, 0xff, 0xf0, 0x00, 0x00, 0x38, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x02, },
+    {0x82, 0x46, 0xc9, 0x99, 0x13, 0x71, 0x86, 0x63,
+     0x2c, 0x5f, 0x9e, 0xdd, 0xf3, 0xb1, 0xb0, 0xe1,
+     0x76, 0x4c, 0x5e, 0x8b, 0xd0, 0xe0, 0xd8, 0xa5,
+     0x54, 0xb9, 0xcb, 0x77, 0xe8, 0x0e, 0xd8, 0x66,
+     0x0b, 0xc1, 0xcb, 0x17, 0xac, 0x7d, 0x84, 0x5b,
+     0xe4, 0x0a, 0x7a, 0x02, 0x2d, 0x33, 0x06, 0xf1,
+     0x16, 0xae, 0x9f, 0x81, 0xfe, 0xa6, 0x59, 0x47,
+    },
+  },
+  {
+    {0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0xff, 0xfe, 0x08, 0x00, 0x00, 0x1f,
+     0xf0, 0x00, 0x1f, 0xff, },
+    {0x66, 0x70, 0xc2, 0x0a, 0xfc, 0xce, 0xae, 0xa6,
+     0x72, 0xc9, 0x7f, 0x75, 0xe2, 0xe9, 0xdd, 0x5c,
+     0x84, 0x60, 0xe5, 0x4b, 0xb3, 0x85, 0x38, 0xeb,
+     0xb4, 0xbd, 0x30, 0xeb, 0xf2, 0x80, 0xd8, 0x00,
+     0x8d, 0x07, 0xa4, 0xca, 0xf5, 0x42, 0x71, 0xf9,
+     0x93, 0x52, 0x7d, 0x46, 0xff, 0x3f, 0xf4, 0x6f,
+     0xd1, 0x19, 0x0a, 0x3f, 0x1f, 0xaa, 0x4f, 0x74,
+    },
+  },
+  {
+    {0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xe0, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff,
+     0xff, 0xff, 0xff, 0xff, },
+    {0x00, 0x0e, 0xca, 0x93, 0x42, 0x47, 0x42, 0x5c,
+     0xfd, 0x94, 0x9b, 0x79, 0x5c, 0xb5, 0xce, 0x1e,
+     0xff, 0x40, 0x15, 0x50, 0x38, 0x6e, 0x28, 0xd1,
+     0xa4, 0xc5, 0xa8, 0xeb, 0xd4, 0xc0, 0x10, 0x40,
+     0xdb, 0xa1, 0x96, 0x28, 0x93, 0x1b, 0xc8, 0x85,
+     0x53, 0x70, 0x31, 0x7c, 0x72, 0x2c, 0xbd, 0x9c,
+     0xa6, 0x15, 0x69, 0x85, 0xf1, 0xc2, 0xe9, 0xce,
+    },
+  },
+  {
+    {0x7f, 0xff, 0xfc, 0x03, 0xff, 0x80, 0x7f, 0xff,
+     0xe0, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x0f, 0xff,
+     0x80, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff,
+     0xff, 0xfe, 0x00, 0x1f, },
+    {0xef, 0x35, 0x3b, 0xf5, 0xc7, 0x3c, 0xd5, 0x51,
+     0xb9, 0x6d, 0x59, 0x6f, 0xbc, 0x9a, 0x67, 0xf1,
+     0x6d, 0x61, 0xdd, 0x9f, 0xe5, 0x6a, 0xf1, 0x9d,
+     0xe1, 0xfb, 0xa9, 0xcd, 0x21, 0x77, 0x1b, 0x9c,
+     0xdc, 0xe3, 0xe8, 0x43, 0x0c, 0x09, 0xb3, 0x83,
+     0x8b, 0xe7, 0x0b, 0x48, 0xc2, 0x1e, 0x15, 0xbc,
+     0x09, 0xee, 0x1f, 0x2d, 0x79, 0x45, 0xb9, 0x1f,
+    },
+  },
+  {
+    {0x00, 0x00, 0x00, 0x07, 0xff, 0xc0, 0x7f, 0xff,
+     0xff, 0xff, 0x01, 0xff, 0xfe, 0x03, 0xff, 0xfe,
+     0x40, 0x00, 0x38, 0x00, 0x07, 0xe0, 0x00, 0x3f,
+     0xfe, 0x00, 0x00, 0x00, },
+    {0x40, 0x36, 0x05, 0x2a, 0x30, 0x91, 0xeb, 0x48,
+     0x10, 0x46, 0xad, 0x32, 0x89, 0xc9, 0x5d, 0x3a,
+     0xc9, 0x05, 0xca, 0x00, 0x23, 0xde, 0x2c, 0x03,
+     0xec, 0xd4, 0x51, 0xcf, 0xd7, 0x68, 0x16, 0x5a,
+     0x38, 0xa2, 0xb9, 0x6f, 0x81, 0x25, 0x86, 0xa9,
+     0xd5, 0x9d, 0x41, 0x36, 0x03, 0x5d, 0x9c, 0x85,
+     0x3a, 0x5b, 0xf2, 0xe1, 0xc8, 0x6a, 0x49, 0x93,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x29, },
+    {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a,
+     0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf,
+     0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee,
+     0xfe, 0x78, 0x24, 0x55, 0xf2, 0xa2, 0x8e, 0xef,
+     0xd8, 0xb3, 0x45, 0x83, 0x21, 0x16, 0xf1, 0xe5,
+     0x74, 0xf2, 0xc6, 0xb2, 0xc8, 0x95, 0xaa, 0x8c,
+     0x24, 0x94, 0x1f, 0x40, 0xd8, 0xb8, 0x0a, 0xd1,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x2a, },
+    {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01,
+     0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc,
+     0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb,
+     0xc6, 0xca, 0xe8, 0x3c, 0x23, 0x0e, 0x09, 0x3c,
+     0x24, 0xf6, 0x38, 0xf5, 0x33, 0xda, 0xc6, 0xe2,
+     0xb6, 0xd0, 0x1d, 0xa3, 0xb5, 0xe7, 0xf4, 0x54,
+     0x29, 0x31, 0x5c, 0xa9, 0x3f, 0xb8, 0xe6, 0x34,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x2b, },
+    {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05,
+     0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea,
+     0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74,
+     0x62, 0x26, 0xe4, 0xcc, 0x15, 0x67, 0x29, 0xf1,
+     0xa0, 0x03, 0x64, 0x70, 0x30, 0x66, 0x60, 0x54,
+     0xe2, 0x08, 0x18, 0x0f, 0x8f, 0x7b, 0x0d, 0xf2,
+     0x24, 0x9e, 0x44, 0xfb, 0xa5, 0x93, 0x1f, 0xff,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x2c, },
+    {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88,
+     0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20,
+     0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c,
+     0x48, 0x44, 0x03, 0xbc, 0x00, 0xeb, 0x61, 0x05,
+     0x99, 0xf9, 0x59, 0x42, 0xdf, 0x10, 0x82, 0xe4,
+     0xf9, 0x42, 0x6d, 0x08, 0x6f, 0xb9, 0xc6, 0x23,
+     0x1a, 0xe8, 0xb2, 0x49, 0x33, 0xaa, 0xb5, 0xdb,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x2d, },
+    {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24,
+     0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c,
+     0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5,
+     0x90, 0xc4, 0xc6, 0x6d, 0xcc, 0x66, 0x2b, 0x9b,
+     0xcb, 0xa6, 0xf9, 0x4e, 0xe4, 0xff, 0x1c, 0x9c,
+     0x10, 0xbd, 0x6d, 0xdd, 0x0d, 0x13, 0x8d, 0xf2,
+     0xd0, 0x99, 0xa2, 0x82, 0x15, 0x2a, 0x4b, 0x7f,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x2e, },
+    {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2,
+     0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29,
+     0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e,
+     0x21, 0x91, 0x6b, 0xf9, 0x68, 0x65, 0xa0, 0xb8,
+     0xa6, 0x07, 0xf0, 0xb0, 0x4b, 0x13, 0xd1, 0xcb,
+     0x0a, 0xa9, 0x92, 0xa5, 0xa9, 0x7f, 0x5e, 0xe8,
+     0xca, 0x18, 0x49, 0xef, 0xb9, 0xed, 0x86, 0x78,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x2f, },
+    {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60,
+     0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2,
+     0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2,
+     0xce, 0x01, 0xe9, 0xfa, 0x2a, 0x7e, 0xb3, 0x28,
+     0xdb, 0xe6, 0x63, 0xb5, 0xa4, 0x68, 0xb5, 0xbc,
+     0x97, 0xa0, 0x40, 0xa3, 0x74, 0x53, 0x96, 0xba,
+     0x63, 0x6b, 0x96, 0x43, 0x70, 0xdc, 0x33, 0x52,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x30, },
+    {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28,
+     0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42,
+     0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98,
+     0x1f, 0xcf, 0xae, 0xca, 0xda, 0xd7, 0xe6, 0x08,
+     0xe3, 0x80, 0x48, 0x04, 0x34, 0xea, 0x64, 0x1c,
+     0xc8, 0x2c, 0x82, 0xcb, 0xc9, 0x28, 0x01, 0x46,
+     0x9c, 0x8d, 0xb0, 0x20, 0x4f, 0x13, 0x48, 0x9a,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x31, },
+    {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b,
+     0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43,
+     0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3,
+     0x04, 0x4f, 0x4f, 0x7a, 0xdf, 0x82, 0x22, 0x0f,
+     0xc7, 0xa4, 0x02, 0x15, 0x49, 0x16, 0x53, 0x25,
+     0x72, 0x5f, 0x94, 0xc3, 0x41, 0x0d, 0xdb, 0x56,
+     0xc5, 0x4e, 0x16, 0x1f, 0xc9, 0xef, 0x62, 0xee,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x32, },
+    {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f,
+     0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50,
+     0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16,
+     0x44, 0x8e, 0x50, 0x7c, 0xdf, 0x4a, 0xef, 0xff,
+     0xbf, 0x6d, 0x16, 0x99, 0xc9, 0x30, 0x48, 0x1c,
+     0xd1, 0x02, 0x12, 0x7c, 0x9a, 0x3d, 0x99, 0x20,
+     0x48, 0xab, 0x05, 0x92, 0x9b, 0x6e, 0x59, 0x27,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x33, },
+    {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb,
+     0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38,
+     0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7,
+     0xbe, 0xe2, 0xc0, 0xfd, 0xc6, 0x44, 0xcf, 0x15,
+     0x4c, 0xc8, 0x1f, 0x5a, 0xde, 0x49, 0x34, 0x5e,
+     0x54, 0x1b, 0x4d, 0x4b, 0x5c, 0x1a, 0xdb, 0x3e,
+     0xb5, 0xc0, 0x1c, 0x14, 0xee, 0x94, 0x9a, 0xa2,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x34, },
+    {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e,
+     0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38,
+     0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36,
+     0xed, 0x15, 0xf7, 0x8d, 0xc8, 0xe8, 0xcd, 0x1b,
+     0x0b, 0xe4, 0x0b, 0x08, 0x77, 0xcf, 0xca, 0x19,
+     0x58, 0x60, 0x31, 0x22, 0xf1, 0xe6, 0x91, 0x4f,
+     0x84, 0xb7, 0xe8, 0xe9, 0x68, 0xae, 0x8b, 0x9e,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x35, },
+    {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31,
+     0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0,
+     0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b,
+     0x55, 0x57, 0x15, 0x50, 0xfb, 0x92, 0x32, 0xc1,
+     0x5a, 0x3b, 0xc7, 0x67, 0x3a, 0x3a, 0x03, 0xb0,
+     0x25, 0x38, 0x24, 0xc5, 0x3d, 0x0f, 0xd1, 0x41,
+     0x1b, 0x1c, 0xab, 0xe2, 0xe1, 0x87, 0xfb, 0x87,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x36, },
+    {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5,
+     0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23,
+     0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24,
+     0xa0, 0x3c, 0x3e, 0x28, 0xf0, 0xc5, 0xcf, 0xf7,
+     0xab, 0x68, 0x0d, 0x09, 0xee, 0x11, 0xda, 0xe8,
+     0x4e, 0x9c, 0x10, 0x72, 0xac, 0x48, 0xea, 0x2e,
+     0x74, 0x4b, 0x1b, 0x7f, 0x72, 0xfd, 0x46, 0x9e,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x37, },
+    {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f,
+     0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d,
+     0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c,
+     0x57, 0x11, 0x24, 0x08, 0x76, 0x05, 0x0f, 0x33,
+     0x48, 0xaf, 0x26, 0x64, 0xaa, 0xc3, 0xa8, 0xb0,
+     0x52, 0x81, 0x30, 0x4e, 0xbc, 0x7a, 0x79, 0x14,
+     0xc6, 0xad, 0x50, 0xa4, 0xb4, 0xea, 0xc3, 0x83,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x38, },
+    {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07,
+     0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90,
+     0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75,
+     0x26, 0xf0, 0x11, 0xaa, 0xd8, 0x17, 0x40, 0x0e,
+     0x8b, 0xa9, 0xca, 0x13, 0xa4, 0x5f, 0x36, 0x0e,
+     0x3d, 0x12, 0x1e, 0xaa, 0xeb, 0x39, 0xaf, 0x82,
+     0xd6, 0x00, 0x1c, 0x81, 0x86, 0xf5, 0xf8, 0x66,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x39, },
+    {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45,
+     0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02,
+     0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e,
+     0x40, 0x44, 0x73, 0x01, 0xfb, 0x7d, 0xa7, 0xf5,
+     0xf1, 0x3a, 0x43, 0xb8, 0x17, 0x74, 0x37, 0x3c,
+     0x87, 0x9c, 0xd3, 0x2d, 0x69, 0x34, 0xc0, 0x5f,
+     0xa7, 0x58, 0xee, 0xb1, 0x4f, 0xcf, 0xab, 0x38,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x3a, },
+    {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3,
+     0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc,
+     0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08,
+     0xfd, 0x89, 0x6d, 0x04, 0x5c, 0x08, 0x0f, 0xc3,
+     0x52, 0x2f, 0x41, 0xbb, 0xb3, 0xf5, 0x5a, 0x97,
+     0xcf, 0xec, 0xf2, 0x1f, 0x88, 0x2c, 0xe8, 0xcb,
+     0xb1, 0xe5, 0x0c, 0xa6, 0xe6, 0x7e, 0x56, 0xdc,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x3b, },
+    {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67,
+     0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88,
+     0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd,
+     0x1a, 0x70, 0x4f, 0xa6, 0xe3, 0xd4, 0x89, 0x58,
+     0x43, 0xda, 0x18, 0x8f, 0xd5, 0x8f, 0xb0, 0x56,
+     0x79, 0x76, 0xd7, 0xb5, 0x03, 0x59, 0xd6, 0xb7,
+     0x85, 0x30, 0xc8, 0xf6, 0x2d, 0x1b, 0x17, 0x46,
+    },
+  },
+  {
+    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2,
+     0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45,
+     0x5c, 0x5c, 0x2a, 0x3c, },
+    {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f,
+     0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3,
+     0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6,
+     0x11, 0x5c, 0x1d, 0x21, 0x42, 0xc8, 0x9c, 0x77,
+     0x4a, 0x08, 0xdc, 0x04, 0xb3, 0xdd, 0x20, 0x19,
+     0x32, 0xbc, 0x8a, 0x5e, 0xa5, 0xf8, 0xb8, 0x9b,
+     0xbb, 0x2a, 0x7e, 0x66, 0x7a, 0xff, 0x81, 0xcd,
+    },
+  },
+};
+
+TEST(P224, ExternalToInternalAndBack) {
+  Point point;
+
+  EXPECT_TRUE(point.SetFromString(base::StringPiece(
+      reinterpret_cast<const char *>(kBasePointExternal),
+      sizeof(kBasePointExternal))));
+
+  const std::string external = point.ToString();
+
+  ASSERT_EQ(external.size(), 56u);
+  EXPECT_TRUE(memcmp(external.data(), kBasePointExternal,
+                     sizeof(kBasePointExternal)) == 0);
+}
+
+TEST(P224, ScalarBaseMult) {
+  Point point;
+
+  for (size_t i = 0; i < arraysize(kNISTTestVectors); i++) {
+    p224::ScalarBaseMult(kNISTTestVectors[i].scalar, &point);
+    const std::string external = point.ToString();
+    ASSERT_EQ(external.size(), 56u);
+    EXPECT_TRUE(memcmp(external.data(), kNISTTestVectors[i].affine,
+                       external.size()) == 0);
+  }
+}
+
+TEST(P224, Addition) {
+  Point a, b, minus_b, sum, a_again;
+
+  ASSERT_TRUE(a.SetFromString(base::StringPiece(
+      reinterpret_cast<const char *>(kNISTTestVectors[10].affine), 56)));
+  ASSERT_TRUE(b.SetFromString(base::StringPiece(
+      reinterpret_cast<const char *>(kNISTTestVectors[11].affine), 56)));
+
+  p224::Negate(b, &minus_b);
+  p224::Add(a, b, &sum);
+  EXPECT_TRUE(memcmp(&sum, &a, sizeof(sum)) != 0);
+  p224::Add(minus_b, sum, &a_again);
+  EXPECT_TRUE(a_again.ToString() == a.ToString());
+}
+
+TEST(P224, Infinity) {
+  char zeros[56];
+  memset(zeros, 0, sizeof(zeros));
+
+  // Test that x^0 = ∞.
+  Point a;
+  p224::ScalarBaseMult(reinterpret_cast<const uint8_t*>(zeros), &a);
+  EXPECT_TRUE(memcmp(zeros, a.ToString().data(), sizeof(zeros)) == 0);
+
+  // We shouldn't allow ∞ to be imported.
+  EXPECT_FALSE(a.SetFromString(std::string(zeros, sizeof(zeros))));
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/random.cc b/libchrome/crypto/random.cc
new file mode 100644
index 0000000..355914e
--- /dev/null
+++ b/libchrome/crypto/random.cc
@@ -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.
+
+#include "crypto/random.h"
+
+#include <stddef.h>
+
+#include "base/rand_util.h"
+
+namespace crypto {
+
+void RandBytes(void *bytes, size_t length) {
+  // It's OK to call base::RandBytes(), because it's already strongly random.
+  // But _other_ code should go through this function to ensure that code which
+  // needs secure randomness is easily discoverable.
+  base::RandBytes(bytes, length);
+}
+
+}  // namespace crypto
+
diff --git a/libchrome/crypto/random.h b/libchrome/crypto/random.h
new file mode 100644
index 0000000..002616b
--- /dev/null
+++ b/libchrome/crypto/random.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 CRYPTO_RANDOM_H_
+#define CRYPTO_RANDOM_H_
+
+#include <stddef.h>
+
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Fills the given buffer with |length| random bytes of cryptographically
+// secure random numbers.
+// |length| must be positive.
+CRYPTO_EXPORT void RandBytes(void *bytes, size_t length);
+
+}
+
+#endif
diff --git a/libchrome/crypto/random_unittest.cc b/libchrome/crypto/random_unittest.cc
new file mode 100644
index 0000000..caee512
--- /dev/null
+++ b/libchrome/crypto/random_unittest.cc
@@ -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.
+
+#include "crypto/random.h"
+
+#include <stddef.h>
+
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Basic functionality tests. Does NOT test the security of the random data.
+
+// Ensures we don't have all trivial data, i.e. that the data is indeed random.
+// Currently, that means the bytes cannot be all the same (e.g. all zeros).
+bool IsTrivial(const std::string& bytes) {
+  for (size_t i = 0; i < bytes.size(); i++) {
+    if (bytes[i] != bytes[0]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+TEST(RandBytes, RandBytes) {
+  std::string bytes(16, '\0');
+  crypto::RandBytes(base::WriteInto(&bytes, bytes.size()), bytes.size());
+  EXPECT_TRUE(!IsTrivial(bytes));
+}
diff --git a/libchrome/crypto/rsa_private_key.cc b/libchrome/crypto/rsa_private_key.cc
new file mode 100644
index 0000000..c546c91
--- /dev/null
+++ b/libchrome/crypto/rsa_private_key.cc
@@ -0,0 +1,389 @@
+// 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 "crypto/rsa_private_key.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+
+// This file manually encodes and decodes RSA private keys using PrivateKeyInfo
+// from PKCS #8 and RSAPrivateKey from PKCS #1. These structures are:
+//
+// PrivateKeyInfo ::= SEQUENCE {
+//   version Version,
+//   privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+//   privateKey PrivateKey,
+//   attributes [0] IMPLICIT Attributes OPTIONAL
+// }
+//
+// RSAPrivateKey ::= SEQUENCE {
+//   version Version,
+//   modulus INTEGER,
+//   publicExponent INTEGER,
+//   privateExponent INTEGER,
+//   prime1 INTEGER,
+//   prime2 INTEGER,
+//   exponent1 INTEGER,
+//   exponent2 INTEGER,
+//   coefficient INTEGER
+// }
+
+namespace {
+// Helper for error handling during key import.
+#define READ_ASSERT(truth) \
+  if (!(truth)) { \
+    NOTREACHED(); \
+    return false; \
+  }
+}  // namespace
+
+namespace crypto {
+
+const uint8_t PrivateKeyInfoCodec::kRsaAlgorithmIdentifier[] = {
+    0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
+    0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00};
+
+PrivateKeyInfoCodec::PrivateKeyInfoCodec(bool big_endian)
+    : big_endian_(big_endian) {}
+
+PrivateKeyInfoCodec::~PrivateKeyInfoCodec() {}
+
+bool PrivateKeyInfoCodec::Export(std::vector<uint8_t>* output) {
+  std::list<uint8_t> content;
+
+  // Version (always zero)
+  uint8_t version = 0;
+
+  PrependInteger(coefficient_, &content);
+  PrependInteger(exponent2_, &content);
+  PrependInteger(exponent1_, &content);
+  PrependInteger(prime2_, &content);
+  PrependInteger(prime1_, &content);
+  PrependInteger(private_exponent_, &content);
+  PrependInteger(public_exponent_, &content);
+  PrependInteger(modulus_, &content);
+  PrependInteger(&version, 1, &content);
+  PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
+  PrependTypeHeaderAndLength(kOctetStringTag, content.size(), &content);
+
+  // RSA algorithm OID
+  for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i)
+    content.push_front(kRsaAlgorithmIdentifier[i - 1]);
+
+  PrependInteger(&version, 1, &content);
+  PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
+
+  // Copy everying into the output.
+  output->reserve(content.size());
+  output->assign(content.begin(), content.end());
+
+  return true;
+}
+
+bool PrivateKeyInfoCodec::ExportPublicKeyInfo(std::vector<uint8_t>* output) {
+  // Create a sequence with the modulus (n) and public exponent (e).
+  std::vector<uint8_t> bit_string;
+  if (!ExportPublicKey(&bit_string))
+    return false;
+
+  // Add the sequence as the contents of a bit string.
+  std::list<uint8_t> content;
+  PrependBitString(&bit_string[0], static_cast<int>(bit_string.size()),
+                   &content);
+
+  // Add the RSA algorithm OID.
+  for (size_t i = sizeof(kRsaAlgorithmIdentifier); i > 0; --i)
+    content.push_front(kRsaAlgorithmIdentifier[i - 1]);
+
+  // Finally, wrap everything in a sequence.
+  PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
+
+  // Copy everything into the output.
+  output->reserve(content.size());
+  output->assign(content.begin(), content.end());
+
+  return true;
+}
+
+bool PrivateKeyInfoCodec::ExportPublicKey(std::vector<uint8_t>* output) {
+  // Create a sequence with the modulus (n) and public exponent (e).
+  std::list<uint8_t> content;
+  PrependInteger(&public_exponent_[0],
+                 static_cast<int>(public_exponent_.size()),
+                 &content);
+  PrependInteger(&modulus_[0],  static_cast<int>(modulus_.size()), &content);
+  PrependTypeHeaderAndLength(kSequenceTag, content.size(), &content);
+
+  // Copy everything into the output.
+  output->reserve(content.size());
+  output->assign(content.begin(), content.end());
+
+  return true;
+}
+
+bool PrivateKeyInfoCodec::Import(const std::vector<uint8_t>& input) {
+  if (input.empty()) {
+    return false;
+  }
+
+  // Parse the private key info up to the public key values, ignoring
+  // the subsequent private key values.
+  uint8_t* src = const_cast<uint8_t*>(&input.front());
+  uint8_t* end = src + input.size();
+  if (!ReadSequence(&src, end) ||
+      !ReadVersion(&src, end) ||
+      !ReadAlgorithmIdentifier(&src, end) ||
+      !ReadTypeHeaderAndLength(&src, end, kOctetStringTag, NULL) ||
+      !ReadSequence(&src, end) ||
+      !ReadVersion(&src, end) ||
+      !ReadInteger(&src, end, &modulus_))
+    return false;
+
+  int mod_size = modulus_.size();
+  READ_ASSERT(mod_size % 2 == 0);
+  int primes_size = mod_size / 2;
+
+  if (!ReadIntegerWithExpectedSize(&src, end, 4, &public_exponent_) ||
+      !ReadIntegerWithExpectedSize(&src, end, mod_size, &private_exponent_) ||
+      !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime1_) ||
+      !ReadIntegerWithExpectedSize(&src, end, primes_size, &prime2_) ||
+      !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent1_) ||
+      !ReadIntegerWithExpectedSize(&src, end, primes_size, &exponent2_) ||
+      !ReadIntegerWithExpectedSize(&src, end, primes_size, &coefficient_))
+    return false;
+
+  READ_ASSERT(src == end);
+
+
+  return true;
+}
+
+void PrivateKeyInfoCodec::PrependInteger(const std::vector<uint8_t>& in,
+                                         std::list<uint8_t>* out) {
+  uint8_t* ptr = const_cast<uint8_t*>(&in.front());
+  PrependIntegerImpl(ptr, in.size(), out, big_endian_);
+}
+
+// Helper to prepend an ASN.1 integer.
+void PrivateKeyInfoCodec::PrependInteger(uint8_t* val,
+                                         int num_bytes,
+                                         std::list<uint8_t>* data) {
+  PrependIntegerImpl(val, num_bytes, data, big_endian_);
+}
+
+void PrivateKeyInfoCodec::PrependIntegerImpl(uint8_t* val,
+                                             int num_bytes,
+                                             std::list<uint8_t>* data,
+                                             bool big_endian) {
+ // Reverse input if little-endian.
+ std::vector<uint8_t> tmp;
+ if (!big_endian) {
+   tmp.assign(val, val + num_bytes);
+   std::reverse(tmp.begin(), tmp.end());
+   val = &tmp.front();
+ }
+
+  // ASN.1 integers are unpadded byte arrays, so skip any null padding bytes
+  // from the most-significant end of the integer.
+  int start = 0;
+  while (start < (num_bytes - 1) && val[start] == 0x00) {
+    start++;
+    num_bytes--;
+  }
+  PrependBytes(val, start, num_bytes, data);
+
+  // ASN.1 integers are signed. To encode a positive integer whose sign bit
+  // (the most significant bit) would otherwise be set and make the number
+  // negative, ASN.1 requires a leading null byte to force the integer to be
+  // positive.
+  uint8_t front = data->front();
+  if ((front & 0x80) != 0) {
+    data->push_front(0x00);
+    num_bytes++;
+  }
+
+  PrependTypeHeaderAndLength(kIntegerTag, num_bytes, data);
+}
+
+bool PrivateKeyInfoCodec::ReadInteger(uint8_t** pos,
+                                      uint8_t* end,
+                                      std::vector<uint8_t>* out) {
+  return ReadIntegerImpl(pos, end, out, big_endian_);
+}
+
+bool PrivateKeyInfoCodec::ReadIntegerWithExpectedSize(
+    uint8_t** pos,
+    uint8_t* end,
+    size_t expected_size,
+    std::vector<uint8_t>* out) {
+  std::vector<uint8_t> temp;
+  if (!ReadIntegerImpl(pos, end, &temp, true))  // Big-Endian
+    return false;
+
+  int pad = expected_size - temp.size();
+  int index = 0;
+  if (out->size() == expected_size + 1) {
+    READ_ASSERT(out->front() == 0x00);
+    pad++;
+    index++;
+  } else {
+    READ_ASSERT(out->size() <= expected_size);
+  }
+
+  out->insert(out->end(), pad, 0x00);
+  out->insert(out->end(), temp.begin(), temp.end());
+
+  // Reverse output if little-endian.
+  if (!big_endian_)
+    std::reverse(out->begin(), out->end());
+  return true;
+}
+
+bool PrivateKeyInfoCodec::ReadIntegerImpl(uint8_t** pos,
+                                          uint8_t* end,
+                                          std::vector<uint8_t>* out,
+                                          bool big_endian) {
+  uint32_t length = 0;
+  if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length) || !length)
+    return false;
+
+  // The first byte can be zero to force positiveness. We can ignore this.
+  if (**pos == 0x00) {
+    ++(*pos);
+    --length;
+  }
+
+  if (length)
+    out->insert(out->end(), *pos, (*pos) + length);
+
+  (*pos) += length;
+
+  // Reverse output if little-endian.
+  if (!big_endian)
+    std::reverse(out->begin(), out->end());
+  return true;
+}
+
+void PrivateKeyInfoCodec::PrependBytes(uint8_t* val,
+                                       int start,
+                                       int num_bytes,
+                                       std::list<uint8_t>* data) {
+  while (num_bytes > 0) {
+    --num_bytes;
+    data->push_front(val[start + num_bytes]);
+  }
+}
+
+void PrivateKeyInfoCodec::PrependLength(size_t size, std::list<uint8_t>* data) {
+  // The high bit is used to indicate whether additional octets are needed to
+  // represent the length.
+  if (size < 0x80) {
+    data->push_front(static_cast<uint8_t>(size));
+  } else {
+    uint8_t num_bytes = 0;
+    while (size > 0) {
+      data->push_front(static_cast<uint8_t>(size & 0xFF));
+      size >>= 8;
+      num_bytes++;
+    }
+    CHECK_LE(num_bytes, 4);
+    data->push_front(0x80 | num_bytes);
+  }
+}
+
+void PrivateKeyInfoCodec::PrependTypeHeaderAndLength(
+    uint8_t type,
+    uint32_t length,
+    std::list<uint8_t>* output) {
+  PrependLength(length, output);
+  output->push_front(type);
+}
+
+void PrivateKeyInfoCodec::PrependBitString(uint8_t* val,
+                                           int num_bytes,
+                                           std::list<uint8_t>* output) {
+  // Start with the data.
+  PrependBytes(val, 0, num_bytes, output);
+  // Zero unused bits.
+  output->push_front(0);
+  // Add the length.
+  PrependLength(num_bytes + 1, output);
+  // Finally, add the bit string tag.
+  output->push_front((uint8_t)kBitStringTag);
+}
+
+bool PrivateKeyInfoCodec::ReadLength(uint8_t** pos,
+                                     uint8_t* end,
+                                     uint32_t* result) {
+  READ_ASSERT(*pos < end);
+  int length = 0;
+
+  // If the MSB is not set, the length is just the byte itself.
+  if (!(**pos & 0x80)) {
+    length = **pos;
+    (*pos)++;
+  } else {
+    // Otherwise, the lower 7 indicate the length of the length.
+    int length_of_length = **pos & 0x7F;
+    READ_ASSERT(length_of_length <= 4);
+    (*pos)++;
+    READ_ASSERT(*pos + length_of_length < end);
+
+    length = 0;
+    for (int i = 0; i < length_of_length; ++i) {
+      length <<= 8;
+      length |= **pos;
+      (*pos)++;
+    }
+  }
+
+  READ_ASSERT(*pos + length <= end);
+  if (result) *result = length;
+  return true;
+}
+
+bool PrivateKeyInfoCodec::ReadTypeHeaderAndLength(uint8_t** pos,
+                                                  uint8_t* end,
+                                                  uint8_t expected_tag,
+                                                  uint32_t* length) {
+  READ_ASSERT(*pos < end);
+  READ_ASSERT(**pos == expected_tag);
+  (*pos)++;
+
+  return ReadLength(pos, end, length);
+}
+
+bool PrivateKeyInfoCodec::ReadSequence(uint8_t** pos, uint8_t* end) {
+  return ReadTypeHeaderAndLength(pos, end, kSequenceTag, NULL);
+}
+
+bool PrivateKeyInfoCodec::ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end) {
+  READ_ASSERT(*pos + sizeof(kRsaAlgorithmIdentifier) < end);
+  READ_ASSERT(memcmp(*pos, kRsaAlgorithmIdentifier,
+                     sizeof(kRsaAlgorithmIdentifier)) == 0);
+  (*pos) += sizeof(kRsaAlgorithmIdentifier);
+  return true;
+}
+
+bool PrivateKeyInfoCodec::ReadVersion(uint8_t** pos, uint8_t* end) {
+  uint32_t length = 0;
+  if (!ReadTypeHeaderAndLength(pos, end, kIntegerTag, &length))
+    return false;
+
+  // The version should be zero.
+  for (uint32_t i = 0; i < length; ++i) {
+    READ_ASSERT(**pos == 0x00);
+    (*pos)++;
+  }
+
+  return true;
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/rsa_private_key.h b/libchrome/crypto/rsa_private_key.h
new file mode 100644
index 0000000..d4808f5
--- /dev/null
+++ b/libchrome/crypto/rsa_private_key.h
@@ -0,0 +1,225 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CRYPTO_RSA_PRIVATE_KEY_H_
+#define CRYPTO_RSA_PRIVATE_KEY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <list>
+#include <vector>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+
+#if defined(USE_OPENSSL)
+// Forward declaration for openssl/*.h
+typedef struct evp_pkey_st EVP_PKEY;
+#else
+// Forward declaration.
+typedef struct PK11SlotInfoStr PK11SlotInfo;
+typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey;
+typedef struct SECKEYPublicKeyStr SECKEYPublicKey;
+#endif
+
+
+namespace crypto {
+
+// Used internally by RSAPrivateKey for serializing and deserializing
+// PKCS #8 PrivateKeyInfo and PublicKeyInfo.
+class PrivateKeyInfoCodec {
+ public:
+  // ASN.1 encoding of the AlgorithmIdentifier from PKCS #8.
+  static const uint8_t kRsaAlgorithmIdentifier[];
+
+  // ASN.1 tags for some types we use.
+  static const uint8_t kBitStringTag = 0x03;
+  static const uint8_t kIntegerTag = 0x02;
+  static const uint8_t kNullTag = 0x05;
+  static const uint8_t kOctetStringTag = 0x04;
+  static const uint8_t kSequenceTag = 0x30;
+
+  // |big_endian| here specifies the byte-significance of the integer components
+  // that will be parsed & serialized (modulus(), etc...) during Import(),
+  // Export() and ExportPublicKeyInfo() -- not the ASN.1 DER encoding of the
+  // PrivateKeyInfo/PublicKeyInfo (which is always big-endian).
+  explicit PrivateKeyInfoCodec(bool big_endian);
+
+  ~PrivateKeyInfoCodec();
+
+  // Exports the contents of the integer components to the ASN.1 DER encoding
+  // of the PrivateKeyInfo structure to |output|.
+  bool Export(std::vector<uint8_t>* output);
+
+  // Exports the contents of the integer components to the ASN.1 DER encoding
+  // of the PublicKeyInfo structure to |output|.
+  bool ExportPublicKeyInfo(std::vector<uint8_t>* output);
+
+  // Exports the contents of the integer components to the ASN.1 DER encoding
+  // of the RSAPublicKey structure to |output|.
+  bool ExportPublicKey(std::vector<uint8_t>* output);
+
+  // Parses the ASN.1 DER encoding of the PrivateKeyInfo structure in |input|
+  // and populates the integer components with |big_endian_| byte-significance.
+  // IMPORTANT NOTE: This is currently *not* security-approved for importing
+  // keys from unstrusted sources.
+  bool Import(const std::vector<uint8_t>& input);
+
+  // Accessors to the contents of the integer components of the PrivateKeyInfo
+  // structure.
+  std::vector<uint8_t>* modulus() { return &modulus_; }
+  std::vector<uint8_t>* public_exponent() { return &public_exponent_; }
+  std::vector<uint8_t>* private_exponent() { return &private_exponent_; }
+  std::vector<uint8_t>* prime1() { return &prime1_; }
+  std::vector<uint8_t>* prime2() { return &prime2_; }
+  std::vector<uint8_t>* exponent1() { return &exponent1_; }
+  std::vector<uint8_t>* exponent2() { return &exponent2_; }
+  std::vector<uint8_t>* coefficient() { return &coefficient_; }
+
+ private:
+  // Utility wrappers for PrependIntegerImpl that use the class's |big_endian_|
+  // value.
+  void PrependInteger(const std::vector<uint8_t>& in, std::list<uint8_t>* out);
+  void PrependInteger(uint8_t* val, int num_bytes, std::list<uint8_t>* data);
+
+  // Prepends the integer stored in |val| - |val + num_bytes| with |big_endian|
+  // byte-significance into |data| as an ASN.1 integer.
+  void PrependIntegerImpl(uint8_t* val,
+                          int num_bytes,
+                          std::list<uint8_t>* data,
+                          bool big_endian);
+
+  // Utility wrappers for ReadIntegerImpl that use the class's |big_endian_|
+  // value.
+  bool ReadInteger(uint8_t** pos, uint8_t* end, std::vector<uint8_t>* out);
+  bool ReadIntegerWithExpectedSize(uint8_t** pos,
+                                   uint8_t* end,
+                                   size_t expected_size,
+                                   std::vector<uint8_t>* out);
+
+  // Reads an ASN.1 integer from |pos|, and stores the result into |out| with
+  // |big_endian| byte-significance.
+  bool ReadIntegerImpl(uint8_t** pos,
+                       uint8_t* end,
+                       std::vector<uint8_t>* out,
+                       bool big_endian);
+
+  // Prepends the integer stored in |val|, starting a index |start|, for
+  // |num_bytes| bytes onto |data|.
+  void PrependBytes(uint8_t* val,
+                    int start,
+                    int num_bytes,
+                    std::list<uint8_t>* data);
+
+  // Helper to prepend an ASN.1 length field.
+  void PrependLength(size_t size, std::list<uint8_t>* data);
+
+  // Helper to prepend an ASN.1 type header.
+  void PrependTypeHeaderAndLength(uint8_t type,
+                                  uint32_t length,
+                                  std::list<uint8_t>* output);
+
+  // Helper to prepend an ASN.1 bit string
+  void PrependBitString(uint8_t* val,
+                        int num_bytes,
+                        std::list<uint8_t>* output);
+
+  // Read an ASN.1 length field. This also checks that the length does not
+  // extend beyond |end|.
+  bool ReadLength(uint8_t** pos, uint8_t* end, uint32_t* result);
+
+  // Read an ASN.1 type header and its length.
+  bool ReadTypeHeaderAndLength(uint8_t** pos,
+                               uint8_t* end,
+                               uint8_t expected_tag,
+                               uint32_t* length);
+
+  // Read an ASN.1 sequence declaration. This consumes the type header and
+  // length field, but not the contents of the sequence.
+  bool ReadSequence(uint8_t** pos, uint8_t* end);
+
+  // Read the RSA AlgorithmIdentifier.
+  bool ReadAlgorithmIdentifier(uint8_t** pos, uint8_t* end);
+
+  // Read one of the two version fields in PrivateKeyInfo.
+  bool ReadVersion(uint8_t** pos, uint8_t* end);
+
+  // The byte-significance of the stored components (modulus, etc..).
+  bool big_endian_;
+
+  // Component integers of the PrivateKeyInfo
+  std::vector<uint8_t> modulus_;
+  std::vector<uint8_t> public_exponent_;
+  std::vector<uint8_t> private_exponent_;
+  std::vector<uint8_t> prime1_;
+  std::vector<uint8_t> prime2_;
+  std::vector<uint8_t> exponent1_;
+  std::vector<uint8_t> exponent2_;
+  std::vector<uint8_t> coefficient_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrivateKeyInfoCodec);
+};
+
+// Encapsulates an RSA private key. Can be used to generate new keys, export
+// keys to other formats, or to extract a public key.
+// TODO(hclam): This class should be ref-counted so it can be reused easily.
+class CRYPTO_EXPORT RSAPrivateKey {
+ public:
+  ~RSAPrivateKey();
+
+  // Create a new random instance. Can return NULL if initialization fails.
+  static RSAPrivateKey* Create(uint16_t num_bits);
+
+  // Create a new instance by importing an existing private key. The format is
+  // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if
+  // initialization fails.
+  static RSAPrivateKey* CreateFromPrivateKeyInfo(
+      const std::vector<uint8_t>& input);
+
+#if defined(USE_OPENSSL)
+  // Create a new instance from an existing EVP_PKEY, taking a
+  // reference to it. |key| must be an RSA key. Returns NULL on
+  // failure.
+  static RSAPrivateKey* CreateFromKey(EVP_PKEY* key);
+#else
+  // Create a new instance by referencing an existing private key
+  // structure.  Does not import the key.
+  static RSAPrivateKey* CreateFromKey(SECKEYPrivateKey* key);
+#endif
+
+#if defined(USE_OPENSSL)
+  EVP_PKEY* key() { return key_; }
+#else
+  SECKEYPrivateKey* key() { return key_; }
+  SECKEYPublicKey* public_key() { return public_key_; }
+#endif
+
+  // Creates a copy of the object.
+  RSAPrivateKey* Copy() const;
+
+  // Exports the private key to a PKCS #8 PrivateKeyInfo block.
+  bool ExportPrivateKey(std::vector<uint8_t>* output) const;
+
+  // Exports the public key to an X509 SubjectPublicKeyInfo block.
+  bool ExportPublicKey(std::vector<uint8_t>* output) const;
+
+ private:
+  // Constructor is private. Use one of the Create*() methods above instead.
+  RSAPrivateKey();
+
+#if defined(USE_OPENSSL)
+  EVP_PKEY* key_;
+#else
+  SECKEYPrivateKey* key_;
+  SECKEYPublicKey* public_key_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(RSAPrivateKey);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_RSA_PRIVATE_KEY_H_
diff --git a/libchrome/crypto/rsa_private_key_nss.cc b/libchrome/crypto/rsa_private_key_nss.cc
new file mode 100644
index 0000000..b1026c1
--- /dev/null
+++ b/libchrome/crypto/rsa_private_key_nss.cc
@@ -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.
+
+#include "crypto/rsa_private_key.h"
+
+#include <cryptohi.h>
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <stdint.h>
+
+#include <list>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "crypto/nss_key_util.h"
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+
+// TODO(rafaelw): Consider using NSS's ASN.1 encoder.
+namespace {
+
+static bool ReadAttribute(SECKEYPrivateKey* key,
+                          CK_ATTRIBUTE_TYPE type,
+                          std::vector<uint8_t>* output) {
+  SECItem item;
+  SECStatus rv;
+  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
+  if (rv != SECSuccess) {
+    NOTREACHED();
+    return false;
+  }
+
+  output->assign(item.data, item.data + item.len);
+  SECITEM_FreeItem(&item, PR_FALSE);
+  return true;
+}
+
+}  // namespace
+
+namespace crypto {
+
+RSAPrivateKey::~RSAPrivateKey() {
+  if (key_)
+    SECKEY_DestroyPrivateKey(key_);
+  if (public_key_)
+    SECKEY_DestroyPublicKey(public_key_);
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::Create(uint16_t num_bits) {
+  EnsureNSSInit();
+
+  ScopedPK11Slot slot(PK11_GetInternalSlot());
+  if (!slot) {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  ScopedSECKEYPublicKey public_key;
+  ScopedSECKEYPrivateKey private_key;
+  if (!GenerateRSAKeyPairNSS(slot.get(), num_bits, false /* not permanent */,
+                             &public_key, &private_key)) {
+    return nullptr;
+  }
+
+  RSAPrivateKey* rsa_key = new RSAPrivateKey;
+  rsa_key->public_key_ = public_key.release();
+  rsa_key->key_ = private_key.release();
+  return rsa_key;
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
+    const std::vector<uint8_t>& input) {
+  EnsureNSSInit();
+
+  ScopedPK11Slot slot(PK11_GetInternalSlot());
+  if (!slot) {
+    NOTREACHED();
+    return nullptr;
+  }
+  ScopedSECKEYPrivateKey key(ImportNSSKeyFromPrivateKeyInfo(
+      slot.get(), input, false /* not permanent */));
+  if (!key || SECKEY_GetPrivateKeyType(key.get()) != rsaKey)
+    return nullptr;
+  return RSAPrivateKey::CreateFromKey(key.get());
+}
+
+// static
+RSAPrivateKey* RSAPrivateKey::CreateFromKey(SECKEYPrivateKey* key) {
+  DCHECK(key);
+  if (SECKEY_GetPrivateKeyType(key) != rsaKey)
+    return NULL;
+  RSAPrivateKey* copy = new RSAPrivateKey();
+  copy->key_ = SECKEY_CopyPrivateKey(key);
+  copy->public_key_ = SECKEY_ConvertToPublicKey(key);
+  if (!copy->key_ || !copy->public_key_) {
+    NOTREACHED();
+    delete copy;
+    return NULL;
+  }
+  return copy;
+}
+
+RSAPrivateKey* RSAPrivateKey::Copy() const {
+  RSAPrivateKey* copy = new RSAPrivateKey();
+  copy->key_ = SECKEY_CopyPrivateKey(key_);
+  copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
+  return copy;
+}
+
+bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const {
+  PrivateKeyInfoCodec private_key_info(true);
+
+  // Manually read the component attributes of the private key and build up
+  // the PrivateKeyInfo.
+  if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
+      !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
+          private_key_info.public_exponent()) ||
+      !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
+          private_key_info.private_exponent()) ||
+      !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
+      !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
+      !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
+      !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
+      !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
+    NOTREACHED();
+    return false;
+  }
+
+  return private_key_info.Export(output);
+}
+
+bool RSAPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const {
+  ScopedSECItem der_pubkey(SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
+  if (!der_pubkey.get()) {
+    NOTREACHED();
+    return false;
+  }
+
+  output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
+  return true;
+}
+
+RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
+  EnsureNSSInit();
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/rsa_private_key_unittest.cc b/libchrome/crypto/rsa_private_key_unittest.cc
new file mode 100644
index 0000000..393a24c
--- /dev/null
+++ b/libchrome/crypto/rsa_private_key_unittest.cc
@@ -0,0 +1,380 @@
+// 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 "crypto/rsa_private_key.h"
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const uint8_t kTestPrivateKeyInfo[] = {
+    0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+    0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+    0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61,
+    0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 0x55, 0x84, 0xd5, 0x3a,
+    0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4,
+    0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 0xb0, 0x40, 0x53, 0x3a,
+    0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f,
+    0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 0xde, 0x4e, 0xb9, 0x57,
+    0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff,
+    0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 0x84, 0x32, 0x33, 0xf3,
+    0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5,
+    0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 0x53, 0x56, 0xa6, 0x83,
+    0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01,
+    0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89, 0x37, 0xcb, 0xf2, 0x98,
+    0xa0, 0xce, 0xb4, 0xcb, 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7,
+    0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd, 0xed, 0xb8, 0x48, 0x8b,
+    0x16, 0x93, 0x36, 0x95, 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6,
+    0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc, 0x43, 0x78, 0xf9, 0xfe,
+    0x1f, 0x33, 0x23, 0x1e, 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b,
+    0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed, 0x86, 0xb2, 0xcb, 0x3c,
+    0xfe, 0x4e, 0xa1, 0xfa, 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38,
+    0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee, 0xa3, 0xf6, 0x85, 0x6b,
+    0x84, 0x43, 0xc9, 0x1e, 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e,
+    0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46, 0x29, 0x5c, 0xc0, 0x4f,
+    0x01, 0x02, 0x41, 0x00, 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c,
+    0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7, 0xcc, 0x61, 0xcd, 0x38,
+    0x42, 0x20, 0xd3, 0x82, 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89,
+    0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42, 0xba, 0x16, 0x1a, 0xea,
+    0x15, 0xc6, 0xf0, 0xb8, 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2,
+    0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81, 0x02, 0x41, 0x00, 0xc0,
+    0x60, 0x62, 0x80, 0xe1, 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72,
+    0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f, 0x7d, 0xd6, 0xb8, 0x31,
+    0x2b, 0x84, 0x7f, 0x62, 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c,
+    0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c, 0x5c, 0x09, 0x3c, 0xcf,
+    0x2f, 0x44, 0x9d, 0xb6, 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b,
+    0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04, 0xe2, 0x0e, 0x56, 0xca,
+    0x03, 0x1a, 0xc0, 0xf9, 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda,
+    0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58, 0xda, 0x55, 0x98, 0x74,
+    0xfc, 0x28, 0x17, 0x93, 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae,
+    0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35, 0xb8, 0x06, 0x03, 0xba,
+    0x08, 0x59, 0x2b, 0x17, 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41,
+    0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30, 0xa0, 0x24, 0xf5, 0xdb,
+    0x2f, 0xf0, 0x2f, 0xf1, 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0,
+    0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d, 0xb4, 0x14, 0xd4, 0x09,
+    0x91, 0x33, 0x5a, 0xfd, 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69,
+    0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39, 0xff, 0x6e, 0xeb, 0xc6,
+    0x86, 0xf5, 0xb4, 0xc7, 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f,
+    0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35, 0x3e, 0x70, 0x8a, 0xbf,
+    0x27, 0x49, 0xb0, 0x99, 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6,
+    0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3, 0xc6, 0xa4, 0x92, 0xd1,
+    0xce, 0x6c, 0x72, 0xfb, 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca,
+    0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3, 0xb1, 0xc5, 0x15, 0xf3};
+
+}  // namespace
+
+// Generate random private keys with two different sizes. Reimport, then
+// export them again. We should get back the same exact bytes.
+TEST(RSAPrivateKeyUnitTest, InitRandomTest) {
+  std::unique_ptr<crypto::RSAPrivateKey> keypair1(
+      crypto::RSAPrivateKey::Create(1024));
+  std::unique_ptr<crypto::RSAPrivateKey> keypair2(
+      crypto::RSAPrivateKey::Create(2048));
+  ASSERT_TRUE(keypair1.get());
+  ASSERT_TRUE(keypair2.get());
+
+  std::vector<uint8_t> privkey1;
+  std::vector<uint8_t> privkey2;
+  std::vector<uint8_t> pubkey1;
+  std::vector<uint8_t> pubkey2;
+
+  ASSERT_TRUE(keypair1->ExportPrivateKey(&privkey1));
+  ASSERT_TRUE(keypair2->ExportPrivateKey(&privkey2));
+  ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1));
+  ASSERT_TRUE(keypair2->ExportPublicKey(&pubkey2));
+
+  std::unique_ptr<crypto::RSAPrivateKey> keypair3(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey1));
+  std::unique_ptr<crypto::RSAPrivateKey> keypair4(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey2));
+  ASSERT_TRUE(keypair3.get());
+  ASSERT_TRUE(keypair4.get());
+
+  std::vector<uint8_t> privkey3;
+  std::vector<uint8_t> privkey4;
+  ASSERT_TRUE(keypair3->ExportPrivateKey(&privkey3));
+  ASSERT_TRUE(keypair4->ExportPrivateKey(&privkey4));
+
+  ASSERT_EQ(privkey1.size(), privkey3.size());
+  ASSERT_EQ(privkey2.size(), privkey4.size());
+  ASSERT_TRUE(0 == memcmp(&privkey1.front(), &privkey3.front(),
+                          privkey1.size()));
+  ASSERT_TRUE(0 == memcmp(&privkey2.front(), &privkey4.front(),
+                          privkey2.size()));
+}
+
+// Test Copy() method.
+TEST(RSAPrivateKeyUnitTest, CopyTest) {
+  std::vector<uint8_t> input(kTestPrivateKeyInfo,
+                             kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo));
+
+  std::unique_ptr<crypto::RSAPrivateKey> key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+
+  std::unique_ptr<crypto::RSAPrivateKey> key_copy(key->Copy());
+  ASSERT_TRUE(key_copy.get());
+
+  std::vector<uint8_t> privkey_copy;
+  ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy));
+  ASSERT_EQ(input, privkey_copy);
+}
+
+// Test that CreateFromPrivateKeyInfo fails if there is extra data after the RSA
+// key.
+TEST(RSAPrivateKeyUnitTest, ExtraData) {
+  std::vector<uint8_t> input(kTestPrivateKeyInfo,
+                             kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo));
+  input.push_back(0);
+
+  std::unique_ptr<crypto::RSAPrivateKey> key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+
+  // Import should fail.
+  EXPECT_FALSE(key);
+}
+
+TEST(RSAPrivateKeyUnitTest, NotRsaKey) {
+  // Defines a valid P-256 private key.
+  const uint8_t kTestEcPrivateKeyInfo[] = {
+      0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86,
+      0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+      0x03, 0x01, 0x07, 0x04, 0x6D, 0x30, 0x6B, 0x02, 0x01, 0x01, 0x04, 0x20,
+      0x1F, 0xE3, 0x39, 0x50, 0xC5, 0xF4, 0x61, 0x12, 0x4A, 0xE9, 0x92, 0xC2,
+      0xBD, 0xFD, 0xF1, 0xC7, 0x3B, 0x16, 0x15, 0xF5, 0x71, 0xBD, 0x56, 0x7E,
+      0x60, 0xD1, 0x9A, 0xA1, 0xF4, 0x8C, 0xDF, 0x42, 0xA1, 0x44, 0x03, 0x42,
+      0x00, 0x04, 0x7C, 0x11, 0x0C, 0x66, 0xDC, 0xFD, 0xA8, 0x07, 0xF6, 0xE6,
+      0x9E, 0x45, 0xDD, 0xB3, 0xC7, 0x4F, 0x69, 0xA1, 0x48, 0x4D, 0x20, 0x3E,
+      0x8D, 0xC5, 0xAD, 0xA8, 0xE9, 0xA9, 0xDD, 0x7C, 0xB3, 0xC7, 0x0D, 0xF4,
+      0x48, 0x98, 0x6E, 0x51, 0xBD, 0xE5, 0xD1, 0x57, 0x6F, 0x99, 0x90, 0x1F,
+      0x9C, 0x2C, 0x6A, 0x80, 0x6A, 0x47, 0xFD, 0x90, 0x76, 0x43, 0xA7, 0x2B,
+      0x83, 0x55, 0x97, 0xEF, 0xC8, 0xC6};
+
+  std::vector<uint8_t> input(
+      kTestEcPrivateKeyInfo,
+      kTestEcPrivateKeyInfo + sizeof(kTestEcPrivateKeyInfo));
+
+  std::unique_ptr<crypto::RSAPrivateKey> key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+
+  // Import should fail as the given PKCS8 bytes were for an EC key not RSA key.
+  EXPECT_FALSE(key);
+}
+
+// Verify that generated public keys look good. This test data was generated
+// with the openssl command line tool.
+TEST(RSAPrivateKeyUnitTest, PublicKeyTest) {
+  const uint8_t expected_public_key_info[] = {
+      0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+      0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
+      0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b,
+      0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08,
+      0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04,
+      0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a,
+      0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30,
+      0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17,
+      0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89,
+      0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85,
+      0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14,
+      0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18,
+      0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6,
+      0x0f, 0x02, 0x03, 0x01, 0x00, 0x01};
+
+  std::vector<uint8_t> input(kTestPrivateKeyInfo,
+                             kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo));
+
+  std::unique_ptr<crypto::RSAPrivateKey> key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
+  ASSERT_TRUE(key.get());
+
+  std::vector<uint8_t> output;
+  ASSERT_TRUE(key->ExportPublicKey(&output));
+
+  ASSERT_TRUE(
+      memcmp(expected_public_key_info, &output.front(), output.size()) == 0);
+}
+
+// These two test keys each contain an integer that has 0x00 for its most
+// significant byte. When encoded as ASN.1, this byte is dropped and there are
+// two interesting sub-cases. When the sign bit of the integer is set, an extra
+// null byte is added back to force the encoded value to be positive. When the
+// sign bit is not set, the encoded integer is just left shorter than usual.
+// See also: http://code.google.com/p/chromium/issues/detail?id=14877.
+//
+// Before we were handling this correctly, we would see one of two failures:
+// * RSAPrivateKey::CreateFromPrivateKeyInfo would return null because the
+//   underlying windows API failed to import the key.
+// * The import would succeed, but incorrectly interpret the data. On export,
+//   the key would contain different values.
+//
+// This test case verifies these two failures modes don't occur.
+TEST(RSAPrivateKeyUnitTest, ShortIntegers) {
+  const uint8_t short_integer_with_high_bit[] = {
+      0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+      0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+      0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+      0x00, 0x92, 0x59, 0x32, 0x7d, 0x8e, 0xaf, 0x2e, 0xd5, 0xb2, 0x5c, 0x67,
+      0xc8, 0x7d, 0x48, 0xb7, 0x84, 0x12, 0xd0, 0x76, 0xda, 0xe1, 0xa3, 0x1e,
+      0x40, 0x01, 0x14, 0x5c, 0xef, 0x26, 0x6e, 0x28, 0xa2, 0xf7, 0xa5, 0xb4,
+      0x02, 0x37, 0xd0, 0x53, 0x10, 0xcb, 0x7c, 0x6a, 0xf4, 0x53, 0x9f, 0xb8,
+      0xe0, 0x83, 0x93, 0xd1, 0x19, 0xd8, 0x28, 0xd1, 0xd1, 0xd8, 0x87, 0x8f,
+      0x92, 0xfd, 0x73, 0xc0, 0x4d, 0x3e, 0x07, 0x22, 0x1f, 0xc1, 0x20, 0xb0,
+      0x70, 0xb2, 0x3b, 0xea, 0xb1, 0xe5, 0x0a, 0xfd, 0x56, 0x49, 0x5e, 0x39,
+      0x90, 0x91, 0xce, 0x04, 0x83, 0x29, 0xaa, 0xfd, 0x12, 0xa4, 0x42, 0x26,
+      0x6c, 0x6e, 0x79, 0x70, 0x77, 0x03, 0xb2, 0x07, 0x01, 0x3d, 0x85, 0x81,
+      0x95, 0x9e, 0xda, 0x5a, 0xa3, 0xf4, 0x2d, 0x38, 0x04, 0x58, 0xf5, 0x6b,
+      0xc9, 0xf1, 0xb5, 0x65, 0xfe, 0x66, 0x0d, 0xa2, 0xd5, 0x02, 0x03, 0x01,
+      0x00, 0x01, 0x02, 0x81, 0x80, 0x5e, 0x01, 0x5f, 0xb6, 0x59, 0x1d, 0xdc,
+      0x36, 0xb6, 0x60, 0x36, 0xe6, 0x08, 0xdb, 0xd9, 0xcd, 0xc3, 0x8c, 0x16,
+      0x9c, 0x98, 0x8d, 0x7f, 0xd3, 0xdb, 0x1d, 0xaa, 0x68, 0x8f, 0xc5, 0xf8,
+      0xe2, 0x5d, 0xb3, 0x19, 0xc2, 0xc6, 0xf9, 0x51, 0x32, 0x1b, 0x93, 0x6a,
+      0xdc, 0x50, 0x8e, 0xeb, 0x61, 0x84, 0x03, 0x42, 0x30, 0x98, 0xb1, 0xf7,
+      0xbd, 0x14, 0x9a, 0x57, 0x36, 0x33, 0x09, 0xd4, 0x3e, 0x90, 0xda, 0xef,
+      0x09, 0x6e, 0xef, 0x49, 0xb6, 0x60, 0x68, 0x5e, 0x54, 0x17, 0x25, 0x5b,
+      0x37, 0xe3, 0x35, 0x63, 0x5b, 0x60, 0x3c, 0xbd, 0x50, 0xdf, 0x46, 0x43,
+      0x08, 0xa4, 0x71, 0x21, 0xf1, 0x30, 0x71, 0xdc, 0xda, 0xd7, 0x6f, 0xd2,
+      0x18, 0xbd, 0x39, 0xf1, 0xe1, 0xbe, 0xa8, 0x8d, 0x62, 0xdf, 0xa2, 0x3e,
+      0xb6, 0x15, 0x26, 0xb6, 0x57, 0xbd, 0x63, 0xdb, 0xc1, 0x91, 0xec, 0xb8,
+      0x01, 0x02, 0x41, 0x00, 0xc6, 0x1a, 0x06, 0x48, 0xf2, 0x12, 0x1c, 0x9f,
+      0x74, 0x20, 0x5c, 0x85, 0xa2, 0xda, 0xe5, 0x62, 0x96, 0x8d, 0x22, 0x7b,
+      0x78, 0x73, 0xea, 0xbb, 0x9f, 0x59, 0x42, 0x13, 0x15, 0xc8, 0x11, 0x50,
+      0x6c, 0x55, 0xf6, 0xdf, 0x8b, 0xfe, 0xc7, 0xdd, 0xa8, 0xca, 0x54, 0x41,
+      0xe8, 0xce, 0xbe, 0x7d, 0xbd, 0xe2, 0x13, 0x4b, 0x5b, 0x61, 0xeb, 0x69,
+      0x6c, 0xb1, 0x9b, 0x28, 0x68, 0x5b, 0xd6, 0x01, 0x02, 0x41, 0x00, 0xbd,
+      0x1e, 0xfe, 0x51, 0x99, 0xb6, 0xe3, 0x84, 0xfe, 0xf1, 0x9e, 0xfd, 0x9c,
+      0xe7, 0x86, 0x43, 0x68, 0x7f, 0x2f, 0x6a, 0x2a, 0x4c, 0xae, 0xa6, 0x41,
+      0x1c, 0xf0, 0x10, 0x37, 0x54, 0x23, 0xba, 0x05, 0x0d, 0x18, 0x27, 0x8d,
+      0xb8, 0xe4, 0x8f, 0xf2, 0x25, 0x73, 0x8a, 0xd7, 0x05, 0x98, 0x6b, 0x3d,
+      0x55, 0xb7, 0x6f, 0x7c, 0xec, 0x77, 0x61, 0x54, 0x7b, 0xb6, 0x6b, 0x31,
+      0xec, 0x94, 0xd5, 0x02, 0x41, 0x00, 0x90, 0xa2, 0xa5, 0x9e, 0x12, 0xa7,
+      0x68, 0xa0, 0x7e, 0xdf, 0xb5, 0xcd, 0x98, 0x26, 0xab, 0xbd, 0xbc, 0x5f,
+      0xd5, 0x22, 0x42, 0xc2, 0x97, 0x4a, 0x5f, 0x40, 0x82, 0xfe, 0x7e, 0x33,
+      0xb1, 0x78, 0x7f, 0x70, 0x90, 0x2b, 0x8d, 0x01, 0xfb, 0x18, 0xfa, 0x48,
+      0xa7, 0x15, 0xec, 0x0d, 0x2e, 0x85, 0x8d, 0xe2, 0x86, 0xe5, 0xc9, 0x15,
+      0x88, 0x14, 0x53, 0xd8, 0xa4, 0x88, 0xef, 0x10, 0xc6, 0x01, 0x02, 0x41,
+      0x00, 0xba, 0xe4, 0xaf, 0x14, 0xfa, 0xdf, 0xf6, 0xd5, 0xce, 0x8f, 0xfe,
+      0xbb, 0xc8, 0x5c, 0x30, 0x9d, 0xda, 0xdd, 0x9d, 0x80, 0xc0, 0x0e, 0x89,
+      0xa5, 0xb8, 0xc1, 0x1d, 0x28, 0x19, 0x55, 0x67, 0xfd, 0x03, 0xd2, 0xdd,
+      0xe4, 0xf0, 0xb4, 0x20, 0x03, 0x74, 0x9b, 0xb8, 0x24, 0x23, 0xbb, 0xde,
+      0xd5, 0x53, 0x86, 0xaa, 0xc1, 0x5d, 0x65, 0xdd, 0xcf, 0xec, 0x8a, 0x59,
+      0x4a, 0x73, 0xca, 0xc5, 0x85, 0x02, 0x40, 0x00, 0xc4, 0x5e, 0x8d, 0xa4,
+      0xea, 0xbb, 0x6a, 0x9b, 0xe6, 0x3a, 0x4d, 0xc1, 0xdb, 0xe5, 0x52, 0x38,
+      0xf9, 0x59, 0x91, 0x2d, 0x90, 0x82, 0xe3, 0x31, 0x1b, 0x48, 0xb7, 0x42,
+      0xfa, 0x1d, 0x83, 0xd5, 0x3d, 0x02, 0xc2, 0x12, 0x71, 0x10, 0x3a, 0xbd,
+      0x92, 0x8f, 0x9b, 0xa2, 0x6b, 0x2d, 0x21, 0xa4, 0x65, 0xe9, 0xfa, 0x8c,
+      0x30, 0x2a, 0x89, 0xce, 0xd0, 0xa7, 0x67, 0xd8, 0x45, 0x84, 0xb0};
+
+  const uint8_t short_integer_without_high_bit[] = {
+      0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+      0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
+      0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+      0x00, 0xc3, 0x9e, 0x8d, 0xc4, 0x6d, 0x38, 0xe8, 0x0e, 0x9f, 0x84, 0x03,
+      0x40, 0x8e, 0x81, 0x2e, 0x56, 0x67, 0x78, 0x11, 0x85, 0x27, 0x81, 0x52,
+      0xf2, 0x1b, 0x3e, 0x5b, 0xf8, 0xab, 0xfc, 0xaf, 0xca, 0x5c, 0x26, 0xd5,
+      0xfa, 0xd4, 0x55, 0x50, 0x38, 0xb9, 0x9d, 0x89, 0x92, 0x7e, 0x34, 0xcf,
+      0x37, 0x82, 0x48, 0x2d, 0xaa, 0xc4, 0x6a, 0x0e, 0x93, 0xea, 0xad, 0x8a,
+      0x33, 0xf0, 0x42, 0x23, 0xe0, 0x4c, 0x98, 0xbf, 0x01, 0x00, 0x1b, 0xfe,
+      0x06, 0x15, 0xc6, 0xe3, 0x80, 0x79, 0x6d, 0xfe, 0x48, 0xcd, 0x40, 0xbb,
+      0xf9, 0x58, 0xe6, 0xbf, 0xd5, 0x4c, 0x29, 0x48, 0x53, 0x78, 0x06, 0x03,
+      0x0d, 0x59, 0xf5, 0x20, 0xe0, 0xe6, 0x8c, 0xb2, 0xf5, 0xd8, 0x61, 0x52,
+      0x7e, 0x40, 0x83, 0xd7, 0x69, 0xae, 0xd7, 0x75, 0x02, 0x2d, 0x49, 0xd5,
+      0x15, 0x5b, 0xf1, 0xd9, 0x4d, 0x60, 0x7d, 0x62, 0xa5, 0x02, 0x03, 0x01,
+      0x00, 0x01, 0x02, 0x7f, 0x6d, 0x45, 0x23, 0xeb, 0x95, 0x17, 0x34, 0x88,
+      0xf6, 0x91, 0xc7, 0x3f, 0x48, 0x5a, 0xe0, 0x87, 0x63, 0x44, 0xae, 0x84,
+      0xb2, 0x8c, 0x8a, 0xc8, 0xb2, 0x6f, 0x22, 0xf0, 0xc5, 0x21, 0x61, 0x10,
+      0xa8, 0x69, 0x09, 0x1e, 0x13, 0x7d, 0x94, 0x52, 0x1b, 0x5c, 0xe4, 0x7b,
+      0xf0, 0x03, 0x8f, 0xbc, 0x72, 0x09, 0xdf, 0x78, 0x84, 0x3e, 0xb9, 0xe5,
+      0xe6, 0x31, 0x0a, 0x01, 0xf9, 0x32, 0xf8, 0xd6, 0x57, 0xa3, 0x87, 0xe6,
+      0xf5, 0x98, 0xbc, 0x8e, 0x41, 0xb9, 0x50, 0x17, 0x7b, 0xd3, 0x97, 0x5a,
+      0x44, 0x3a, 0xee, 0xff, 0x6b, 0xb3, 0x3a, 0x52, 0xe7, 0xa4, 0x96, 0x9a,
+      0xf6, 0x83, 0xc8, 0x97, 0x1c, 0x63, 0xa1, 0xd6, 0xb3, 0xa8, 0xb2, 0xc7,
+      0x73, 0x25, 0x0f, 0x58, 0x36, 0xb9, 0x7a, 0x47, 0xa7, 0x4d, 0x30, 0xfe,
+      0x4d, 0x74, 0x56, 0xe8, 0xfb, 0xd6, 0x50, 0xe5, 0xe0, 0x28, 0x15, 0x02,
+      0x41, 0x00, 0xeb, 0x15, 0x62, 0xb6, 0x37, 0x41, 0x7c, 0xc5, 0x00, 0x22,
+      0x2c, 0x5a, 0x5e, 0xe4, 0xb2, 0x11, 0x87, 0x89, 0xad, 0xf4, 0x57, 0x68,
+      0x90, 0xb7, 0x9f, 0xe2, 0x79, 0x20, 0x6b, 0x98, 0x00, 0x0d, 0x3a, 0x3b,
+      0xc1, 0xcd, 0x36, 0xf9, 0x27, 0xda, 0x40, 0x36, 0x1d, 0xb8, 0x5c, 0x96,
+      0xeb, 0x04, 0x08, 0xe1, 0x3f, 0xfa, 0x94, 0x8b, 0x0f, 0xa0, 0xff, 0xc1,
+      0x51, 0xea, 0x90, 0xad, 0x15, 0xc7, 0x02, 0x41, 0x00, 0xd5, 0x06, 0x45,
+      0xd7, 0x55, 0x63, 0x1a, 0xf0, 0x89, 0x81, 0xae, 0x87, 0x23, 0xa2, 0x39,
+      0xfe, 0x3d, 0x82, 0xc7, 0xcb, 0x15, 0xb9, 0xe3, 0xe2, 0x5b, 0xc6, 0xd2,
+      0x55, 0xdd, 0xab, 0x55, 0x29, 0x7c, 0xda, 0x0e, 0x1c, 0x09, 0xfc, 0x73,
+      0x0d, 0x01, 0xed, 0x6d, 0x2f, 0x05, 0xd0, 0xd5, 0x1d, 0xce, 0x18, 0x7f,
+      0xb0, 0xc8, 0x47, 0x77, 0xd2, 0xa9, 0x9e, 0xfc, 0x39, 0x4b, 0x3d, 0x94,
+      0x33, 0x02, 0x41, 0x00, 0x8f, 0x94, 0x09, 0x2d, 0x17, 0x44, 0x75, 0x0a,
+      0xf1, 0x10, 0xee, 0x1b, 0xe7, 0xd7, 0x2f, 0xf6, 0xca, 0xdc, 0x49, 0x15,
+      0x72, 0x09, 0x58, 0x51, 0xfe, 0x61, 0xd8, 0xee, 0xf7, 0x27, 0xe7, 0xe8,
+      0x2c, 0x47, 0xf1, 0x0f, 0x00, 0x63, 0x5e, 0x76, 0xcb, 0x3f, 0x02, 0x19,
+      0xe6, 0xda, 0xfa, 0x01, 0x05, 0xd7, 0x65, 0x37, 0x0b, 0x60, 0x7f, 0x94,
+      0x2a, 0x80, 0x8d, 0x22, 0x81, 0x68, 0x65, 0x63, 0x02, 0x41, 0x00, 0xc2,
+      0xd4, 0x18, 0xde, 0x47, 0x9e, 0xfb, 0x8d, 0x91, 0x05, 0xc5, 0x3c, 0x9d,
+      0xcf, 0x8a, 0x60, 0xc7, 0x9b, 0x2b, 0xe5, 0xc6, 0xba, 0x1b, 0xfc, 0xf3,
+      0xd9, 0x54, 0x97, 0xe9, 0xc4, 0x00, 0x80, 0x90, 0x4a, 0xd2, 0x6a, 0xbc,
+      0x8b, 0x62, 0x22, 0x3c, 0x68, 0x0c, 0xda, 0xdb, 0xe3, 0xd2, 0x76, 0x8e,
+      0xff, 0x03, 0x12, 0x09, 0x2a, 0xac, 0x21, 0x44, 0xb7, 0x3e, 0x91, 0x9c,
+      0x09, 0xf6, 0xd7, 0x02, 0x41, 0x00, 0xc0, 0xa1, 0xbb, 0x70, 0xdc, 0xf8,
+      0xeb, 0x17, 0x61, 0xd4, 0x8c, 0x7c, 0x3b, 0x82, 0x91, 0x58, 0xff, 0xf9,
+      0x19, 0xac, 0x3a, 0x73, 0xa7, 0x20, 0xe5, 0x22, 0x02, 0xc4, 0xf6, 0xb9,
+      0xb9, 0x43, 0x53, 0x35, 0x88, 0xe1, 0x05, 0xb6, 0x43, 0x9b, 0x39, 0xc8,
+      0x04, 0x4d, 0x2b, 0x01, 0xf7, 0xe6, 0x1b, 0x8d, 0x7e, 0x89, 0xe3, 0x43,
+      0xd4, 0xf3, 0xab, 0x28, 0xd4, 0x5a, 0x1f, 0x20, 0xea, 0xbe};
+
+  std::vector<uint8_t> input1;
+  std::vector<uint8_t> input2;
+
+  input1.resize(sizeof(short_integer_with_high_bit));
+  input2.resize(sizeof(short_integer_without_high_bit));
+
+  memcpy(&input1.front(), short_integer_with_high_bit,
+         sizeof(short_integer_with_high_bit));
+  memcpy(&input2.front(), short_integer_without_high_bit,
+         sizeof(short_integer_without_high_bit));
+
+  std::unique_ptr<crypto::RSAPrivateKey> keypair1(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input1));
+  std::unique_ptr<crypto::RSAPrivateKey> keypair2(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input2));
+  ASSERT_TRUE(keypair1.get());
+  ASSERT_TRUE(keypair2.get());
+
+  std::vector<uint8_t> output1;
+  std::vector<uint8_t> output2;
+  ASSERT_TRUE(keypair1->ExportPrivateKey(&output1));
+  ASSERT_TRUE(keypair2->ExportPrivateKey(&output2));
+
+  ASSERT_EQ(input1.size(), output1.size());
+  ASSERT_EQ(input2.size(), output2.size());
+  ASSERT_TRUE(0 == memcmp(&output1.front(), &input1.front(),
+                          input1.size()));
+  ASSERT_TRUE(0 == memcmp(&output2.front(), &input2.front(),
+                          input2.size()));
+}
+
+TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) {
+  std::unique_ptr<crypto::RSAPrivateKey> key_pair(
+      crypto::RSAPrivateKey::Create(512));
+  ASSERT_TRUE(key_pair.get());
+
+  std::unique_ptr<crypto::RSAPrivateKey> key_copy(
+      crypto::RSAPrivateKey::CreateFromKey(key_pair->key()));
+  ASSERT_TRUE(key_copy.get());
+
+  std::vector<uint8_t> privkey;
+  std::vector<uint8_t> pubkey;
+  ASSERT_TRUE(key_pair->ExportPrivateKey(&privkey));
+  ASSERT_TRUE(key_pair->ExportPublicKey(&pubkey));
+
+  std::vector<uint8_t> privkey_copy;
+  std::vector<uint8_t> pubkey_copy;
+  ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy));
+  ASSERT_TRUE(key_copy->ExportPublicKey(&pubkey_copy));
+
+  ASSERT_EQ(privkey, privkey_copy);
+  ASSERT_EQ(pubkey, pubkey_copy);
+}
+
diff --git a/libchrome/crypto/scoped_capi_types.h b/libchrome/crypto/scoped_capi_types.h
new file mode 100644
index 0000000..74e5765
--- /dev/null
+++ b/libchrome/crypto/scoped_capi_types.h
@@ -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.
+
+#ifndef CRYPTO_SCOPED_CAPI_TYPES_H_
+#define CRYPTO_SCOPED_CAPI_TYPES_H_
+
+#include <windows.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "crypto/wincrypt_shim.h"
+
+namespace crypto {
+
+// Simple destructor for the Free family of CryptoAPI functions, such as
+// CryptDestroyHash, which take only a single argument to release.
+template <typename CAPIHandle, BOOL (WINAPI *Destroyer)(CAPIHandle)>
+struct CAPIDestroyer {
+  void operator()(CAPIHandle handle) const {
+    if (handle) {
+      BOOL ok = Destroyer(handle);
+      DCHECK(ok);
+    }
+  }
+};
+
+// Destructor for the Close/Release family of CryptoAPI functions, which take
+// a second DWORD parameter indicating flags to use when closing or releasing.
+// This includes functions like CertCloseStore or CryptReleaseContext.
+template <typename CAPIHandle, BOOL (WINAPI *Destroyer)(CAPIHandle, DWORD),
+          DWORD flags>
+struct CAPIDestroyerWithFlags {
+  void operator()(CAPIHandle handle) const {
+    if (handle) {
+      BOOL ok = Destroyer(handle, flags);
+      DCHECK(ok);
+    }
+  }
+};
+
+// scoped_ptr-like class for the CryptoAPI cryptography and certificate
+// handles. Because these handles are defined as integer types, and not
+// pointers, the existing scoped classes, such as scoped_ptr, are insufficient.
+// The semantics are the same as scoped_ptr.
+template <class CAPIHandle, typename FreeProc>
+class ScopedCAPIHandle {
+ public:
+  explicit ScopedCAPIHandle(CAPIHandle handle = NULL) : handle_(handle) {}
+
+  ~ScopedCAPIHandle() {
+    reset();
+  }
+
+  void reset(CAPIHandle handle = NULL) {
+    if (handle_ != handle) {
+      FreeProc free_proc;
+      free_proc(handle_);
+      handle_ = handle;
+    }
+  }
+
+  operator CAPIHandle() const { return handle_; }
+  CAPIHandle get() const { return handle_; }
+
+  CAPIHandle* receive() {
+    CHECK(handle_ == NULL);
+    return &handle_;
+  }
+
+  bool operator==(CAPIHandle handle) const {
+    return handle_ == handle;
+  }
+
+  bool operator!=(CAPIHandle handle) const {
+    return handle_ != handle;
+  }
+
+  void swap(ScopedCAPIHandle& b) {
+    CAPIHandle tmp = b.handle_;
+    b.handle_ = handle_;
+    handle_ = tmp;
+  }
+
+  CAPIHandle release() {
+    CAPIHandle tmp = handle_;
+    handle_ = NULL;
+    return tmp;
+  }
+
+ private:
+  CAPIHandle handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCAPIHandle);
+};
+
+template<class CH, typename FP> inline
+bool operator==(CH h, const ScopedCAPIHandle<CH, FP>& b) {
+  return h == b.get();
+}
+
+template<class CH, typename FP> inline
+bool operator!=(CH h, const ScopedCAPIHandle<CH, FP>& b) {
+  return h != b.get();
+}
+
+typedef ScopedCAPIHandle<
+    HCRYPTPROV,
+    CAPIDestroyerWithFlags<HCRYPTPROV,
+                           CryptReleaseContext, 0> > ScopedHCRYPTPROV;
+
+typedef ScopedCAPIHandle<
+    HCRYPTKEY, CAPIDestroyer<HCRYPTKEY, CryptDestroyKey> > ScopedHCRYPTKEY;
+
+typedef ScopedCAPIHandle<
+    HCRYPTHASH, CAPIDestroyer<HCRYPTHASH, CryptDestroyHash> > ScopedHCRYPTHASH;
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SCOPED_CAPI_TYPES_H_
diff --git a/libchrome/crypto/scoped_nss_types.h b/libchrome/crypto/scoped_nss_types.h
new file mode 100644
index 0000000..a739565
--- /dev/null
+++ b/libchrome/crypto/scoped_nss_types.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 CRYPTO_SCOPED_NSS_TYPES_H_
+#define CRYPTO_SCOPED_NSS_TYPES_H_
+
+#include <keyhi.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <plarena.h>
+
+#include <memory>
+
+namespace crypto {
+
+template <typename Type, void (*Destroyer)(Type*)>
+struct NSSDestroyer {
+  void operator()(Type* ptr) const {
+    Destroyer(ptr);
+  }
+};
+
+template <typename Type, void (*Destroyer)(Type*, PRBool), PRBool freeit>
+struct NSSDestroyer1 {
+  void operator()(Type* ptr) const {
+    Destroyer(ptr, freeit);
+  }
+};
+
+// Define some convenient scopers around NSS pointers.
+typedef std::unique_ptr<
+    PK11Context,
+    NSSDestroyer1<PK11Context, PK11_DestroyContext, PR_TRUE>>
+    ScopedPK11Context;
+typedef std::unique_ptr<PK11SlotInfo, NSSDestroyer<PK11SlotInfo, PK11_FreeSlot>>
+    ScopedPK11Slot;
+typedef std::unique_ptr<PK11SlotList,
+                        NSSDestroyer<PK11SlotList, PK11_FreeSlotList>>
+    ScopedPK11SlotList;
+typedef std::unique_ptr<PK11SymKey, NSSDestroyer<PK11SymKey, PK11_FreeSymKey>>
+    ScopedPK11SymKey;
+typedef std::unique_ptr<SECKEYPublicKey,
+                        NSSDestroyer<SECKEYPublicKey, SECKEY_DestroyPublicKey>>
+    ScopedSECKEYPublicKey;
+typedef std::unique_ptr<
+    SECKEYPrivateKey,
+    NSSDestroyer<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>>
+    ScopedSECKEYPrivateKey;
+typedef std::unique_ptr<
+    SECAlgorithmID,
+    NSSDestroyer1<SECAlgorithmID, SECOID_DestroyAlgorithmID, PR_TRUE>>
+    ScopedSECAlgorithmID;
+typedef std::unique_ptr<SECItem,
+                        NSSDestroyer1<SECItem, SECITEM_FreeItem, PR_TRUE>>
+    ScopedSECItem;
+typedef std::unique_ptr<PLArenaPool,
+                        NSSDestroyer1<PLArenaPool, PORT_FreeArena, PR_FALSE>>
+    ScopedPLArenaPool;
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SCOPED_NSS_TYPES_H_
diff --git a/libchrome/crypto/scoped_openssl_types.h b/libchrome/crypto/scoped_openssl_types.h
new file mode 100644
index 0000000..622fed2
--- /dev/null
+++ b/libchrome/crypto/scoped_openssl_types.h
@@ -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.
+
+#ifndef CRYPTO_SCOPED_OPENSSL_TYPES_H_
+#define CRYPTO_SCOPED_OPENSSL_TYPES_H_
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/mem.h>
+#endif
+#include <openssl/rsa.h>
+#include <stdint.h>
+
+#include <memory>
+
+namespace crypto {
+
+// Simplistic helper that wraps a call to a deleter function. In a C++11 world,
+// this would be std::function<>. An alternative would be to re-use
+// base::internal::RunnableAdapter<>, but that's far too heavy weight.
+template <typename Type, void (*Destroyer)(Type*)>
+struct OpenSSLDestroyer {
+  void operator()(Type* ptr) const { Destroyer(ptr); }
+};
+
+template <typename PointerType, void (*Destroyer)(PointerType*)>
+using ScopedOpenSSL =
+    std::unique_ptr<PointerType, OpenSSLDestroyer<PointerType, Destroyer>>;
+
+struct OpenSSLFree {
+  void operator()(uint8_t* ptr) const { OPENSSL_free(ptr); }
+};
+
+// Several typedefs are provided for crypto-specific primitives, for
+// short-hand and prevalence. Note that OpenSSL types related to X.509 are
+// intentionally not included, as crypto/ does not generally deal with
+// certificates or PKI.
+using ScopedBIGNUM = ScopedOpenSSL<BIGNUM, BN_free>;
+using ScopedEC_Key = ScopedOpenSSL<EC_KEY, EC_KEY_free>;
+using ScopedBIO = ScopedOpenSSL<BIO, BIO_free_all>;
+using ScopedDSA = ScopedOpenSSL<DSA, DSA_free>;
+using ScopedECDSA_SIG = ScopedOpenSSL<ECDSA_SIG, ECDSA_SIG_free>;
+using ScopedEC_GROUP = ScopedOpenSSL<EC_GROUP, EC_GROUP_free>;
+using ScopedEC_KEY = ScopedOpenSSL<EC_KEY, EC_KEY_free>;
+using ScopedEC_POINT = ScopedOpenSSL<EC_POINT, EC_POINT_free>;
+using ScopedEVP_MD_CTX = ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy>;
+using ScopedEVP_PKEY = ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free>;
+using ScopedEVP_PKEY_CTX = ScopedOpenSSL<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
+using ScopedRSA = ScopedOpenSSL<RSA, RSA_free>;
+
+// The bytes must have been allocated with OPENSSL_malloc.
+using ScopedOpenSSLBytes = std::unique_ptr<uint8_t, OpenSSLFree>;
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SCOPED_OPENSSL_TYPES_H_
diff --git a/libchrome/crypto/scoped_test_nss_chromeos_user.cc b/libchrome/crypto/scoped_test_nss_chromeos_user.cc
new file mode 100644
index 0000000..aec25d8
--- /dev/null
+++ b/libchrome/crypto/scoped_test_nss_chromeos_user.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 "crypto/scoped_test_nss_chromeos_user.h"
+
+#include "base/logging.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+
+namespace crypto {
+
+ScopedTestNSSChromeOSUser::ScopedTestNSSChromeOSUser(
+    const std::string& username_hash)
+    : username_hash_(username_hash), constructed_successfully_(false) {
+  if (!temp_dir_.CreateUniqueTempDir())
+    return;
+  // This opens a software DB in the given folder. In production code that is in
+  // the home folder, but for testing the temp folder is used.
+  constructed_successfully_ =
+      InitializeNSSForChromeOSUser(username_hash, temp_dir_.path());
+}
+
+ScopedTestNSSChromeOSUser::~ScopedTestNSSChromeOSUser() {
+  if (constructed_successfully_)
+    CloseChromeOSUserForTesting(username_hash_);
+}
+
+void ScopedTestNSSChromeOSUser::FinishInit() {
+  DCHECK(constructed_successfully_);
+  if (!ShouldInitializeTPMForChromeOSUser(username_hash_))
+    return;
+  WillInitializeTPMForChromeOSUser(username_hash_);
+  InitializePrivateSoftwareSlotForChromeOSUser(username_hash_);
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/scoped_test_nss_chromeos_user.h b/libchrome/crypto/scoped_test_nss_chromeos_user.h
new file mode 100644
index 0000000..9202b0f
--- /dev/null
+++ b/libchrome/crypto/scoped_test_nss_chromeos_user.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 CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_
+#define CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_
+
+#include <string>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Opens a persistent NSS software database in a temporary directory for the
+// user with |username_hash|. This database will be used for both the user's
+// public and private slot.
+class CRYPTO_EXPORT ScopedTestNSSChromeOSUser {
+ public:
+  // Opens the software database and sets the public slot for the user. The
+  // private slot will not be initialized until FinishInit() is called.
+  explicit ScopedTestNSSChromeOSUser(const std::string& username_hash);
+  ~ScopedTestNSSChromeOSUser();
+
+  std::string username_hash() const { return username_hash_; }
+  bool constructed_successfully() const { return constructed_successfully_; }
+
+  // Completes initialization of user. Causes any waiting private slot callbacks
+  // to run, see GetPrivateSlotForChromeOSUser().
+  void FinishInit();
+
+ private:
+  const std::string username_hash_;
+  base::ScopedTempDir temp_dir_;
+  bool constructed_successfully_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTestNSSChromeOSUser);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SCOPED_TEST_NSS_CHROMEOS_USER_H_
diff --git a/libchrome/crypto/scoped_test_nss_db.cc b/libchrome/crypto/scoped_test_nss_db.cc
new file mode 100644
index 0000000..dc58031
--- /dev/null
+++ b/libchrome/crypto/scoped_test_nss_db.cc
@@ -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.
+
+#include "crypto/scoped_test_nss_db.h"
+
+#include <cert.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+
+namespace crypto {
+
+ScopedTestNSSDB::ScopedTestNSSDB() {
+  EnsureNSSInit();
+  // NSS is allowed to do IO on the current thread since dispatching
+  // to a dedicated thread would still have the affect of blocking
+  // the current thread, due to NSS's internal locking requirements
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  if (!temp_dir_.CreateUniqueTempDir())
+    return;
+
+  const char kTestDescription[] = "Test DB";
+  slot_ = OpenSoftwareNSSDB(temp_dir_.path(), kTestDescription);
+}
+
+ScopedTestNSSDB::~ScopedTestNSSDB() {
+  // Remove trust from any certs in the test DB before closing it. Otherwise NSS
+  // may cache verification results even after the test DB is gone.
+  if (slot_) {
+    CERTCertList* cert_list = PK11_ListCertsInSlot(slot_.get());
+    for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
+         !CERT_LIST_END(node, cert_list);
+         node = CERT_LIST_NEXT(node)) {
+      CERTCertTrust trust = {0};
+      if (CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), node->cert, &trust) !=
+          SECSuccess) {
+        LOG(ERROR) << "CERT_ChangeCertTrust failed: " << PORT_GetError();
+      }
+    }
+    CERT_DestroyCertList(cert_list);
+  }
+
+  // Don't close when NSS is < 3.15.1, because it would require an additional
+  // sleep for 1 second after closing the database, due to
+  // http://bugzil.la/875601.
+  if (!NSS_VersionCheck("3.15.1")) {
+    LOG(ERROR) << "NSS version is < 3.15.1, test DB will not be closed.";
+    temp_dir_.Take();
+    return;
+  }
+
+  // NSS is allowed to do IO on the current thread since dispatching
+  // to a dedicated thread would still have the affect of blocking
+  // the current thread, due to NSS's internal locking requirements
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  if (slot_) {
+    SECStatus status = SECMOD_CloseUserDB(slot_.get());
+    if (status != SECSuccess)
+      PLOG(ERROR) << "SECMOD_CloseUserDB failed: " << PORT_GetError();
+  }
+
+  if (!temp_dir_.Delete())
+    LOG(ERROR) << "Could not delete temporary directory.";
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/scoped_test_nss_db.h b/libchrome/crypto/scoped_test_nss_db.h
new file mode 100644
index 0000000..c01653f
--- /dev/null
+++ b/libchrome/crypto/scoped_test_nss_db.h
@@ -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.
+
+#ifndef CRYPTO_SCOPED_TEST_NSS_DB_H_
+#define CRYPTO_SCOPED_TEST_NSS_DB_H_
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "crypto/crypto_export.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace crypto {
+
+// Opens a persistent NSS database in a temporary directory.
+// Prior NSS version 3.15.1, because of http://bugzil.la/875601 , the opened DB
+// will not be closed automatically.
+class CRYPTO_EXPORT ScopedTestNSSDB {
+ public:
+  ScopedTestNSSDB();
+  ~ScopedTestNSSDB();
+
+  bool is_open() const { return !!slot_; }
+  PK11SlotInfo* slot() const { return slot_.get(); }
+
+ private:
+  base::ScopedTempDir temp_dir_;
+  ScopedPK11Slot slot_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTestNSSDB);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SCOPED_TEST_NSS_DB_H_
diff --git a/libchrome/crypto/scoped_test_system_nss_key_slot.cc b/libchrome/crypto/scoped_test_system_nss_key_slot.cc
new file mode 100644
index 0000000..53fbbff
--- /dev/null
+++ b/libchrome/crypto/scoped_test_system_nss_key_slot.cc
@@ -0,0 +1,32 @@
+// 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 "crypto/scoped_test_system_nss_key_slot.h"
+
+#include "crypto/nss_util_internal.h"
+#include "crypto/scoped_test_nss_db.h"
+
+namespace crypto {
+
+ScopedTestSystemNSSKeySlot::ScopedTestSystemNSSKeySlot()
+    : test_db_(new ScopedTestNSSDB) {
+  if (!test_db_->is_open())
+    return;
+  SetSystemKeySlotForTesting(
+      ScopedPK11Slot(PK11_ReferenceSlot(test_db_->slot())));
+}
+
+ScopedTestSystemNSSKeySlot::~ScopedTestSystemNSSKeySlot() {
+  SetSystemKeySlotForTesting(ScopedPK11Slot());
+}
+
+bool ScopedTestSystemNSSKeySlot::ConstructedSuccessfully() const {
+  return test_db_->is_open();
+}
+
+PK11SlotInfo* ScopedTestSystemNSSKeySlot::slot() const {
+  return test_db_->slot();
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/scoped_test_system_nss_key_slot.h b/libchrome/crypto/scoped_test_system_nss_key_slot.h
new file mode 100644
index 0000000..eb8fbc9
--- /dev/null
+++ b/libchrome/crypto/scoped_test_system_nss_key_slot.h
@@ -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.
+
+#ifndef CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_
+#define CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "crypto/crypto_export.h"
+
+// Forward declaration, from <pk11pub.h>
+typedef struct PK11SlotInfoStr PK11SlotInfo;
+
+namespace crypto {
+
+class ScopedTestNSSDB;
+
+// Opens a persistent NSS software database in a temporary directory and sets
+// the test system slot to the opened database. This helper should be created in
+// tests to fake the system token that is usually provided by the Chaps module.
+// |slot| is exposed through |GetSystemNSSKeySlot| and |IsTPMTokenReady| will
+// return true.
+// |InitializeTPMTokenAndSystemSlot|, which triggers the TPM initialization,
+// does not have to be called if this helper is used.
+// At most one instance of this helper must be used at a time.
+class CRYPTO_EXPORT ScopedTestSystemNSSKeySlot {
+ public:
+  explicit ScopedTestSystemNSSKeySlot();
+  ~ScopedTestSystemNSSKeySlot();
+
+  bool ConstructedSuccessfully() const;
+  PK11SlotInfo* slot() const;
+
+ private:
+  std::unique_ptr<ScopedTestNSSDB> test_db_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTestSystemNSSKeySlot);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SCOPED_TEST_SYSTEM_NSS_KEY_SLOT_H_
diff --git a/libchrome/crypto/secure_hash.cc b/libchrome/crypto/secure_hash.cc
new file mode 100644
index 0000000..9003b9c
--- /dev/null
+++ b/libchrome/crypto/secure_hash.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crypto/secure_hash.h"
+
+#if defined(OPENSSL_IS_BORINGSSL)
+#include <openssl/mem.h>
+#else
+#include <openssl/crypto.h>
+#endif
+#include <openssl/sha.h>
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/pickle.h"
+#include "crypto/openssl_util.h"
+
+namespace crypto {
+
+namespace {
+
+class SecureHashSHA256 : public SecureHash {
+ public:
+  SecureHashSHA256() {
+    SHA256_Init(&ctx_);
+  }
+
+  SecureHashSHA256(const SecureHashSHA256& other) : SecureHash() {
+    memcpy(&ctx_, &other.ctx_, sizeof(ctx_));
+  }
+
+  ~SecureHashSHA256() override {
+    OPENSSL_cleanse(&ctx_, sizeof(ctx_));
+  }
+
+  void Update(const void* input, size_t len) override {
+    SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len);
+  }
+
+  void Finish(void* output, size_t len) override {
+    ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result(
+        static_cast<unsigned char*>(output), len);
+    SHA256_Final(result.safe_buffer(), &ctx_);
+  }
+
+  std::unique_ptr<SecureHash> Clone() const override {
+    return base::MakeUnique<SecureHashSHA256>(*this);
+  }
+
+  size_t GetHashLength() const override { return SHA256_DIGEST_LENGTH; }
+
+ private:
+  SHA256_CTX ctx_;
+};
+
+}  // namespace
+
+std::unique_ptr<SecureHash> SecureHash::Create(Algorithm algorithm) {
+  switch (algorithm) {
+    case SHA256:
+      return base::MakeUnique<SecureHashSHA256>();
+    default:
+      NOTIMPLEMENTED();
+      return nullptr;
+  }
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/secure_hash.h b/libchrome/crypto/secure_hash.h
new file mode 100644
index 0000000..30b9fdc
--- /dev/null
+++ b/libchrome/crypto/secure_hash.h
@@ -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.
+
+#ifndef CRYPTO_SECURE_HASH_H_
+#define CRYPTO_SECURE_HASH_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// A wrapper to calculate secure hashes incrementally, allowing to
+// be used when the full input is not known in advance.
+class CRYPTO_EXPORT SecureHash {
+ public:
+  enum Algorithm {
+    SHA256,
+  };
+  virtual ~SecureHash() {}
+
+  static std::unique_ptr<SecureHash> Create(Algorithm type);
+
+  virtual void Update(const void* input, size_t len) = 0;
+  virtual void Finish(void* output, size_t len) = 0;
+  virtual size_t GetHashLength() const = 0;
+
+  // Create a clone of this SecureHash. The returned clone and this both
+  // represent the same hash state. But from this point on, calling
+  // Update()/Finish() on either doesn't affect the state of the other.
+  virtual std::unique_ptr<SecureHash> Clone() const = 0;
+
+ protected:
+  SecureHash() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SecureHash);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SECURE_HASH_H_
diff --git a/libchrome/crypto/secure_hash_unittest.cc b/libchrome/crypto/secure_hash_unittest.cc
new file mode 100644
index 0000000..cb9f585
--- /dev/null
+++ b/libchrome/crypto/secure_hash_unittest.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 "crypto/secure_hash.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "crypto/sha2.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SecureHashTest, TestUpdate) {
+  // Example B.3 from FIPS 180-2: long message.
+  std::string input3(500000, 'a');  // 'a' repeated half a million times
+  const int kExpectedHashOfInput3[] = {
+      0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7,
+      0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97,
+      0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0};
+
+  uint8_t output3[crypto::kSHA256Length];
+
+  std::unique_ptr<crypto::SecureHash> ctx(
+      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+  ctx->Update(input3.data(), input3.size());
+  ctx->Update(input3.data(), input3.size());
+
+  ctx->Finish(output3, sizeof(output3));
+  for (size_t i = 0; i < crypto::kSHA256Length; i++)
+    EXPECT_EQ(kExpectedHashOfInput3[i], static_cast<int>(output3[i]));
+}
+
+TEST(SecureHashTest, TestClone) {
+  std::string input1(10001, 'a');  // 'a' repeated 10001 times
+  std::string input2(10001, 'd');  // 'd' repeated 10001 times
+
+  const uint8_t kExpectedHashOfInput1[crypto::kSHA256Length] = {
+      0x0c, 0xab, 0x99, 0xa0, 0x58, 0x60, 0x0f, 0xfa, 0xad, 0x12, 0x92,
+      0xd0, 0xc5, 0x3c, 0x05, 0x48, 0xeb, 0xaf, 0x88, 0xdd, 0x1d, 0x01,
+      0x03, 0x03, 0x45, 0x70, 0x5f, 0x01, 0x8a, 0x81, 0x39, 0x09};
+  const uint8_t kExpectedHashOfInput1And2[crypto::kSHA256Length] = {
+      0x4c, 0x8e, 0x26, 0x5a, 0xc3, 0x85, 0x1f, 0x1f, 0xa5, 0x04, 0x1c,
+      0xc7, 0x88, 0x53, 0x1c, 0xc7, 0x80, 0x47, 0x15, 0xfb, 0x47, 0xff,
+      0x72, 0xb1, 0x28, 0x37, 0xb0, 0x4d, 0x6e, 0x22, 0x2e, 0x4d};
+
+  uint8_t output1[crypto::kSHA256Length];
+  uint8_t output2[crypto::kSHA256Length];
+  uint8_t output3[crypto::kSHA256Length];
+
+  std::unique_ptr<crypto::SecureHash> ctx1(
+      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+  ctx1->Update(input1.data(), input1.size());
+
+  std::unique_ptr<crypto::SecureHash> ctx2(ctx1->Clone());
+  std::unique_ptr<crypto::SecureHash> ctx3(ctx2->Clone());
+  // At this point, ctx1, ctx2, and ctx3 are all equivalent and represent the
+  // state after hashing input1.
+
+  // Updating ctx1 and ctx2 with input2 should produce equivalent results.
+  ctx1->Update(input2.data(), input2.size());
+  ctx1->Finish(output1, sizeof(output1));
+
+  ctx2->Update(input2.data(), input2.size());
+  ctx2->Finish(output2, sizeof(output2));
+
+  EXPECT_EQ(0, memcmp(output1, output2, crypto::kSHA256Length));
+  EXPECT_EQ(0,
+            memcmp(output1, kExpectedHashOfInput1And2, crypto::kSHA256Length));
+
+  // Finish() ctx3, which should produce the hash of input1.
+  ctx3->Finish(&output3, sizeof(output3));
+  EXPECT_EQ(0, memcmp(output3, kExpectedHashOfInput1, crypto::kSHA256Length));
+}
+
+TEST(SecureHashTest, TestLength) {
+  std::unique_ptr<crypto::SecureHash> ctx(
+      crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+  EXPECT_EQ(crypto::kSHA256Length, ctx->GetHashLength());
+}
diff --git a/libchrome/crypto/secure_util.cc b/libchrome/crypto/secure_util.cc
new file mode 100644
index 0000000..fe86d65
--- /dev/null
+++ b/libchrome/crypto/secure_util.cc
@@ -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.
+
+#include <stddef.h>
+
+#include "crypto/secure_util.h"
+
+namespace crypto {
+
+bool SecureMemEqual(const void* s1, const void* s2, size_t n) {
+  const unsigned char* s1_ptr = reinterpret_cast<const unsigned char*>(s1);
+  const unsigned char* s2_ptr = reinterpret_cast<const unsigned char*>(s2);
+  unsigned char tmp = 0;
+  for (size_t i = 0; i < n; ++i, ++s1_ptr, ++s2_ptr)
+    tmp |= *s1_ptr ^ *s2_ptr;
+  return (tmp == 0);
+}
+
+}  // namespace crypto
+
diff --git a/libchrome/crypto/secure_util.h b/libchrome/crypto/secure_util.h
new file mode 100644
index 0000000..cfe05ca
--- /dev/null
+++ b/libchrome/crypto/secure_util.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 CRYPTO_SECURE_UTIL_H_
+#define CRYPTO_SECURE_UTIL_H_
+
+#include <stddef.h>
+
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// Performs a constant-time comparison of two strings, returning true if the
+// strings are equal.
+//
+// For cryptographic operations, comparison functions such as memcmp() may
+// expose side-channel information about input, allowing an attacker to
+// perform timing analysis to determine what the expected bits should be. In
+// order to avoid such attacks, the comparison must execute in constant time,
+// so as to not to reveal to the attacker where the difference(s) are.
+// For an example attack, see
+// http://groups.google.com/group/keyczar-discuss/browse_thread/thread/5571eca0948b2a13
+CRYPTO_EXPORT bool SecureMemEqual(const void* s1, const void* s2, size_t n);
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SECURE_UTIL_H_
+
diff --git a/libchrome/crypto/sha2.cc b/libchrome/crypto/sha2.cc
new file mode 100644
index 0000000..e97b8f4
--- /dev/null
+++ b/libchrome/crypto/sha2.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 "crypto/sha2.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/stl_util.h"
+#include "crypto/secure_hash.h"
+
+namespace crypto {
+
+void SHA256HashString(const base::StringPiece& str, void* output, size_t len) {
+  std::unique_ptr<SecureHash> ctx(SecureHash::Create(SecureHash::SHA256));
+  ctx->Update(str.data(), str.length());
+  ctx->Finish(output, len);
+}
+
+std::string SHA256HashString(const base::StringPiece& str) {
+  std::string output(kSHA256Length, 0);
+  SHA256HashString(str, string_as_array(&output), output.size());
+  return output;
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/sha2.h b/libchrome/crypto/sha2.h
new file mode 100644
index 0000000..d575815
--- /dev/null
+++ b/libchrome/crypto/sha2.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 CRYPTO_SHA2_H_
+#define CRYPTO_SHA2_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "crypto/crypto_export.h"
+
+namespace crypto {
+
+// These functions perform SHA-256 operations.
+//
+// Functions for SHA-384 and SHA-512 can be added when the need arises.
+
+static const size_t kSHA256Length = 32;  // Length in bytes of a SHA-256 hash.
+
+// Computes the SHA-256 hash of the input string 'str' and stores the first
+// 'len' bytes of the hash in the output buffer 'output'.  If 'len' > 32,
+// only 32 bytes (the full hash) are stored in the 'output' buffer.
+CRYPTO_EXPORT void SHA256HashString(const base::StringPiece& str,
+                                    void* output, size_t len);
+
+// Convenience version of the above that returns the result in a 32-byte
+// string.
+CRYPTO_EXPORT std::string SHA256HashString(const base::StringPiece& str);
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SHA2_H_
diff --git a/libchrome/crypto/sha2_unittest.cc b/libchrome/crypto/sha2_unittest.cc
new file mode 100644
index 0000000..27d6d25
--- /dev/null
+++ b/libchrome/crypto/sha2_unittest.cc
@@ -0,0 +1,102 @@
+// 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 "crypto/sha2.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(Sha256Test, Test1) {
+  // Example B.1 from FIPS 180-2: one-block message.
+  std::string input1 = "abc";
+  int expected1[] = { 0xba, 0x78, 0x16, 0xbf,
+                      0x8f, 0x01, 0xcf, 0xea,
+                      0x41, 0x41, 0x40, 0xde,
+                      0x5d, 0xae, 0x22, 0x23,
+                      0xb0, 0x03, 0x61, 0xa3,
+                      0x96, 0x17, 0x7a, 0x9c,
+                      0xb4, 0x10, 0xff, 0x61,
+                      0xf2, 0x00, 0x15, 0xad };
+
+  uint8_t output1[crypto::kSHA256Length];
+  crypto::SHA256HashString(input1, output1, sizeof(output1));
+  for (size_t i = 0; i < crypto::kSHA256Length; i++)
+    EXPECT_EQ(expected1[i], static_cast<int>(output1[i]));
+
+  uint8_t output_truncated1[4];  // 4 bytes == 32 bits
+  crypto::SHA256HashString(input1,
+                           output_truncated1, sizeof(output_truncated1));
+  for (size_t i = 0; i < sizeof(output_truncated1); i++)
+    EXPECT_EQ(expected1[i], static_cast<int>(output_truncated1[i]));
+}
+
+TEST(Sha256Test, Test1_String) {
+  // Same as the above, but using the wrapper that returns a std::string.
+  // Example B.1 from FIPS 180-2: one-block message.
+  std::string input1 = "abc";
+  int expected1[] = { 0xba, 0x78, 0x16, 0xbf,
+                      0x8f, 0x01, 0xcf, 0xea,
+                      0x41, 0x41, 0x40, 0xde,
+                      0x5d, 0xae, 0x22, 0x23,
+                      0xb0, 0x03, 0x61, 0xa3,
+                      0x96, 0x17, 0x7a, 0x9c,
+                      0xb4, 0x10, 0xff, 0x61,
+                      0xf2, 0x00, 0x15, 0xad };
+
+  std::string output1 = crypto::SHA256HashString(input1);
+  ASSERT_EQ(crypto::kSHA256Length, output1.size());
+  for (size_t i = 0; i < crypto::kSHA256Length; i++)
+    EXPECT_EQ(expected1[i], static_cast<uint8_t>(output1[i]));
+}
+
+TEST(Sha256Test, Test2) {
+  // Example B.2 from FIPS 180-2: multi-block message.
+  std::string input2 =
+      "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+  int expected2[] = { 0x24, 0x8d, 0x6a, 0x61,
+                      0xd2, 0x06, 0x38, 0xb8,
+                      0xe5, 0xc0, 0x26, 0x93,
+                      0x0c, 0x3e, 0x60, 0x39,
+                      0xa3, 0x3c, 0xe4, 0x59,
+                      0x64, 0xff, 0x21, 0x67,
+                      0xf6, 0xec, 0xed, 0xd4,
+                      0x19, 0xdb, 0x06, 0xc1 };
+
+  uint8_t output2[crypto::kSHA256Length];
+  crypto::SHA256HashString(input2, output2, sizeof(output2));
+  for (size_t i = 0; i < crypto::kSHA256Length; i++)
+    EXPECT_EQ(expected2[i], static_cast<int>(output2[i]));
+
+  uint8_t output_truncated2[6];
+  crypto::SHA256HashString(input2,
+                           output_truncated2, sizeof(output_truncated2));
+  for (size_t i = 0; i < sizeof(output_truncated2); i++)
+    EXPECT_EQ(expected2[i], static_cast<int>(output_truncated2[i]));
+}
+
+TEST(Sha256Test, Test3) {
+  // Example B.3 from FIPS 180-2: long message.
+  std::string input3(1000000, 'a');  // 'a' repeated a million times
+  int expected3[] = { 0xcd, 0xc7, 0x6e, 0x5c,
+                      0x99, 0x14, 0xfb, 0x92,
+                      0x81, 0xa1, 0xc7, 0xe2,
+                      0x84, 0xd7, 0x3e, 0x67,
+                      0xf1, 0x80, 0x9a, 0x48,
+                      0xa4, 0x97, 0x20, 0x0e,
+                      0x04, 0x6d, 0x39, 0xcc,
+                      0xc7, 0x11, 0x2c, 0xd0 };
+
+  uint8_t output3[crypto::kSHA256Length];
+  crypto::SHA256HashString(input3, output3, sizeof(output3));
+  for (size_t i = 0; i < crypto::kSHA256Length; i++)
+    EXPECT_EQ(expected3[i], static_cast<int>(output3[i]));
+
+  uint8_t output_truncated3[12];
+  crypto::SHA256HashString(input3,
+                           output_truncated3, sizeof(output_truncated3));
+  for (size_t i = 0; i < sizeof(output_truncated3); i++)
+    EXPECT_EQ(expected3[i], static_cast<int>(output_truncated3[i]));
+}
diff --git a/libchrome/crypto/signature_creator.h b/libchrome/crypto/signature_creator.h
new file mode 100644
index 0000000..1e8e856
--- /dev/null
+++ b/libchrome/crypto/signature_creator.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 CRYPTO_SIGNATURE_CREATOR_H_
+#define CRYPTO_SIGNATURE_CREATOR_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+
+#if defined(USE_OPENSSL)
+// Forward declaration for openssl/*.h
+typedef struct env_md_ctx_st EVP_MD_CTX;
+#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
+// Forward declaration.
+struct SGNContextStr;
+#endif
+
+namespace crypto {
+
+class RSAPrivateKey;
+
+// Signs data using a bare private key (as opposed to a full certificate).
+// Currently can only sign data using SHA-1 or SHA-256 with RSA PKCS#1v1.5.
+class CRYPTO_EXPORT SignatureCreator {
+ public:
+  // The set of supported hash functions. Extend as required.
+  enum HashAlgorithm {
+    SHA1,
+    SHA256,
+  };
+
+  ~SignatureCreator();
+
+  // Create an instance. The caller must ensure that the provided PrivateKey
+  // instance outlives the created SignatureCreator. Uses the HashAlgorithm
+  // specified.
+  static std::unique_ptr<SignatureCreator> Create(RSAPrivateKey* key,
+                                                  HashAlgorithm hash_alg);
+
+  // Signs the precomputed |hash_alg| digest |data| using private |key| as
+  // specified in PKCS #1 v1.5.
+  static bool Sign(RSAPrivateKey* key,
+                   HashAlgorithm hash_alg,
+                   const uint8_t* data,
+                   int data_len,
+                   std::vector<uint8_t>* signature);
+
+  // Update the signature with more data.
+  bool Update(const uint8_t* data_part, int data_part_len);
+
+  // Finalize the signature.
+  bool Final(std::vector<uint8_t>* signature);
+
+ private:
+  // Private constructor. Use the Create() method instead.
+  SignatureCreator();
+
+#if defined(USE_OPENSSL)
+  EVP_MD_CTX* sign_context_;
+#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
+  SGNContextStr* sign_context_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(SignatureCreator);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SIGNATURE_CREATOR_H_
diff --git a/libchrome/crypto/signature_creator_nss.cc b/libchrome/crypto/signature_creator_nss.cc
new file mode 100644
index 0000000..bf20413
--- /dev/null
+++ b/libchrome/crypto/signature_creator_nss.cc
@@ -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.
+
+#include "crypto/signature_creator.h"
+
+#include <cryptohi.h>
+#include <keyhi.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "crypto/nss_util.h"
+#include "crypto/rsa_private_key.h"
+
+namespace crypto {
+
+namespace {
+
+SECOidTag ToNSSSigOid(SignatureCreator::HashAlgorithm hash_alg) {
+  switch (hash_alg) {
+    case SignatureCreator::SHA1:
+      return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+    case SignatureCreator::SHA256:
+      return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+  }
+  return SEC_OID_UNKNOWN;
+}
+
+SECOidTag ToNSSHashOid(SignatureCreator::HashAlgorithm hash_alg) {
+  switch (hash_alg) {
+    case SignatureCreator::SHA1:
+      return SEC_OID_SHA1;
+    case SignatureCreator::SHA256:
+      return SEC_OID_SHA256;
+  }
+  return SEC_OID_UNKNOWN;
+}
+
+}  // namespace
+
+SignatureCreator::~SignatureCreator() {
+  if (sign_context_) {
+    SGN_DestroyContext(sign_context_, PR_TRUE);
+    sign_context_ = NULL;
+  }
+}
+
+// static
+SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key,
+                                           HashAlgorithm hash_alg) {
+  scoped_ptr<SignatureCreator> result(new SignatureCreator);
+  result->sign_context_ = SGN_NewContext(ToNSSSigOid(hash_alg), key->key());
+  if (!result->sign_context_) {
+    NOTREACHED();
+    return NULL;
+  }
+
+  SECStatus rv = SGN_Begin(result->sign_context_);
+  if (rv != SECSuccess) {
+    NOTREACHED();
+    return NULL;
+  }
+
+  return result.release();
+}
+
+// static
+bool SignatureCreator::Sign(RSAPrivateKey* key,
+                            HashAlgorithm hash_alg,
+                            const uint8_t* data,
+                            int data_len,
+                            std::vector<uint8_t>* signature) {
+  SECItem data_item;
+  data_item.type = siBuffer;
+  data_item.data = const_cast<unsigned char*>(data);
+  data_item.len = data_len;
+
+  SECItem signature_item;
+  SECStatus rv = SGN_Digest(key->key(), ToNSSHashOid(hash_alg), &signature_item,
+                            &data_item);
+  if (rv != SECSuccess) {
+    NOTREACHED();
+    return false;
+  }
+  signature->assign(signature_item.data,
+                    signature_item.data + signature_item.len);
+  SECITEM_FreeItem(&signature_item, PR_FALSE);
+  return true;
+}
+
+bool SignatureCreator::Update(const uint8_t* data_part, int data_part_len) {
+  SECStatus rv = SGN_Update(sign_context_, data_part, data_part_len);
+  if (rv != SECSuccess) {
+    NOTREACHED();
+    return false;
+  }
+
+  return true;
+}
+
+bool SignatureCreator::Final(std::vector<uint8_t>* signature) {
+  SECItem signature_item;
+  SECStatus rv = SGN_End(sign_context_, &signature_item);
+  if (rv != SECSuccess) {
+    return false;
+  }
+  signature->assign(signature_item.data,
+                    signature_item.data + signature_item.len);
+  SECITEM_FreeItem(&signature_item, PR_FALSE);
+  return true;
+}
+
+SignatureCreator::SignatureCreator() : sign_context_(NULL) {
+  EnsureNSSInit();
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/signature_creator_unittest.cc b/libchrome/crypto/signature_creator_unittest.cc
new file mode 100644
index 0000000..819e663
--- /dev/null
+++ b/libchrome/crypto/signature_creator_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 "crypto/signature_creator.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/sha1.h"
+#include "crypto/rsa_private_key.h"
+#include "crypto/sha2.h"
+#include "crypto/signature_verifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SignatureCreatorTest, BasicTest) {
+  // Do a verify round trip.
+  std::unique_ptr<crypto::RSAPrivateKey> key_original(
+      crypto::RSAPrivateKey::Create(1024));
+  ASSERT_TRUE(key_original.get());
+
+  std::vector<uint8_t> key_info;
+  key_original->ExportPrivateKey(&key_info);
+  std::unique_ptr<crypto::RSAPrivateKey> key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
+  ASSERT_TRUE(key.get());
+
+  std::unique_ptr<crypto::SignatureCreator> signer(
+      crypto::SignatureCreator::Create(key.get(),
+                                       crypto::SignatureCreator::SHA1));
+  ASSERT_TRUE(signer.get());
+
+  std::string data("Hello, World!");
+  ASSERT_TRUE(signer->Update(reinterpret_cast<const uint8_t*>(data.c_str()),
+                             data.size()));
+
+  std::vector<uint8_t> signature;
+  ASSERT_TRUE(signer->Final(&signature));
+
+  std::vector<uint8_t> public_key_info;
+  ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
+
+  crypto::SignatureVerifier verifier;
+  ASSERT_TRUE(verifier.VerifyInit(
+      crypto::SignatureVerifier::RSA_PKCS1_SHA1, &signature.front(),
+      signature.size(), &public_key_info.front(), public_key_info.size()));
+
+  verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(data.c_str()),
+                        data.size());
+  ASSERT_TRUE(verifier.VerifyFinal());
+}
+
+TEST(SignatureCreatorTest, SignDigestTest) {
+  // Do a verify round trip.
+  std::unique_ptr<crypto::RSAPrivateKey> key_original(
+      crypto::RSAPrivateKey::Create(1024));
+  ASSERT_TRUE(key_original.get());
+
+  std::vector<uint8_t> key_info;
+  key_original->ExportPrivateKey(&key_info);
+  std::unique_ptr<crypto::RSAPrivateKey> key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
+  ASSERT_TRUE(key.get());
+
+  std::string data("Hello, World!");
+  std::string sha1 = base::SHA1HashString(data);
+  // Sign sha1 of the input data.
+  std::vector<uint8_t> signature;
+  ASSERT_TRUE(crypto::SignatureCreator::Sign(
+      key.get(), crypto::SignatureCreator::SHA1,
+      reinterpret_cast<const uint8_t*>(sha1.c_str()), sha1.size(), &signature));
+
+  std::vector<uint8_t> public_key_info;
+  ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
+
+  // Verify the input data.
+  crypto::SignatureVerifier verifier;
+  ASSERT_TRUE(verifier.VerifyInit(
+      crypto::SignatureVerifier::RSA_PKCS1_SHA1, &signature.front(),
+      signature.size(), &public_key_info.front(), public_key_info.size()));
+
+  verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(data.c_str()),
+                        data.size());
+  ASSERT_TRUE(verifier.VerifyFinal());
+}
+
+TEST(SignatureCreatorTest, SignSHA256DigestTest) {
+  // Do a verify round trip.
+  std::unique_ptr<crypto::RSAPrivateKey> key_original(
+      crypto::RSAPrivateKey::Create(1024));
+  ASSERT_TRUE(key_original.get());
+
+  std::vector<uint8_t> key_info;
+  key_original->ExportPrivateKey(&key_info);
+  std::unique_ptr<crypto::RSAPrivateKey> key(
+      crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
+  ASSERT_TRUE(key.get());
+
+  std::string data("Hello, World!");
+  std::string sha256 = crypto::SHA256HashString(data);
+  // Sign sha256 of the input data.
+  std::vector<uint8_t> signature;
+  ASSERT_TRUE(crypto::SignatureCreator::Sign(
+      key.get(), crypto::SignatureCreator::HashAlgorithm::SHA256,
+      reinterpret_cast<const uint8_t*>(sha256.c_str()), sha256.size(),
+      &signature));
+
+  std::vector<uint8_t> public_key_info;
+  ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
+
+  // Verify the input data.
+  crypto::SignatureVerifier verifier;
+  ASSERT_TRUE(verifier.VerifyInit(
+      crypto::SignatureVerifier::RSA_PKCS1_SHA256, &signature.front(),
+      signature.size(), &public_key_info.front(), public_key_info.size()));
+
+  verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(data.c_str()),
+                        data.size());
+  ASSERT_TRUE(verifier.VerifyFinal());
+}
diff --git a/libchrome/crypto/signature_verifier.h b/libchrome/crypto/signature_verifier.h
new file mode 100644
index 0000000..5b7369f
--- /dev/null
+++ b/libchrome/crypto/signature_verifier.h
@@ -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.
+
+#ifndef CRYPTO_SIGNATURE_VERIFIER_H_
+#define CRYPTO_SIGNATURE_VERIFIER_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+
+#if defined(USE_OPENSSL)
+typedef struct env_md_st EVP_MD;
+typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
+#else
+typedef struct HASHContextStr HASHContext;
+typedef struct SECKEYPublicKeyStr SECKEYPublicKey;
+typedef struct VFYContextStr VFYContext;
+#endif
+
+namespace crypto {
+
+// The SignatureVerifier class verifies a signature using a bare public key
+// (as opposed to a certificate).
+class CRYPTO_EXPORT SignatureVerifier {
+ public:
+  // The set of supported hash functions. Extend as required.
+  enum HashAlgorithm {
+    SHA1,
+    SHA256,
+  };
+
+  // The set of supported signature algorithms. Extend as required.
+  enum SignatureAlgorithm {
+    RSA_PKCS1_SHA1,
+    RSA_PKCS1_SHA256,
+    ECDSA_SHA256,
+  };
+
+  SignatureVerifier();
+  ~SignatureVerifier();
+
+  // Streaming interface:
+
+  // Initiates a signature verification operation.  This should be followed
+  // by one or more VerifyUpdate calls and a VerifyFinal call.
+  // NOTE: for RSA-PSS signatures, use VerifyInitRSAPSS instead.
+  //
+  // The signature is encoded according to the signature algorithm.
+  //
+  // The public key is specified as a DER encoded ASN.1 SubjectPublicKeyInfo
+  // structure, which contains not only the public key but also its type
+  // (algorithm):
+  //   SubjectPublicKeyInfo  ::=  SEQUENCE  {
+  //       algorithm            AlgorithmIdentifier,
+  //       subjectPublicKey     BIT STRING  }
+  bool VerifyInit(SignatureAlgorithm signature_algorithm,
+                  const uint8_t* signature,
+                  int signature_len,
+                  const uint8_t* public_key_info,
+                  int public_key_info_len);
+
+  // Initiates a RSA-PSS signature verification operation.  This should be
+  // followed by one or more VerifyUpdate calls and a VerifyFinal call.
+  //
+  // The RSA-PSS signature algorithm parameters are specified with the
+  // |hash_alg|, |mask_hash_alg|, and |salt_len| arguments.
+  //
+  // An RSA-PSS signature is a nonnegative integer encoded as a byte string
+  // (of the same length as the RSA modulus) in big-endian byte order. It
+  // must not be further encoded in an ASN.1 BIT STRING.
+  //
+  // The public key is specified as a DER encoded ASN.1 SubjectPublicKeyInfo
+  // structure, which contains not only the public key but also its type
+  // (algorithm):
+  //   SubjectPublicKeyInfo  ::=  SEQUENCE  {
+  //       algorithm            AlgorithmIdentifier,
+  //       subjectPublicKey     BIT STRING  }
+  bool VerifyInitRSAPSS(HashAlgorithm hash_alg,
+                        HashAlgorithm mask_hash_alg,
+                        int salt_len,
+                        const uint8_t* signature,
+                        int signature_len,
+                        const uint8_t* public_key_info,
+                        int public_key_info_len);
+
+  // Feeds a piece of the data to the signature verifier.
+  void VerifyUpdate(const uint8_t* data_part, int data_part_len);
+
+  // Concludes a signature verification operation.  Returns true if the
+  // signature is valid.  Returns false if the signature is invalid or an
+  // error occurred.
+  bool VerifyFinal();
+
+ private:
+#if defined(USE_OPENSSL)
+  bool CommonInit(int pkey_type,
+                  const EVP_MD* digest,
+                  const uint8_t* signature,
+                  int signature_len,
+                  const uint8_t* public_key_info,
+                  int public_key_info_len,
+                  EVP_PKEY_CTX** pkey_ctx);
+#else
+  static SECKEYPublicKey* DecodePublicKeyInfo(const uint8_t* public_key_info,
+                                              int public_key_info_len);
+#endif
+
+  void Reset();
+
+  std::vector<uint8_t> signature_;
+
+#if defined(USE_OPENSSL)
+  struct VerifyContext;
+  VerifyContext* verify_context_;
+#else
+  // Used for all signature types except RSA-PSS.
+  VFYContext* vfy_context_;
+
+  // Used for RSA-PSS signatures.
+  HashAlgorithm hash_alg_;
+  HashAlgorithm mask_hash_alg_;
+  unsigned int salt_len_;
+  SECKEYPublicKey* public_key_;
+  HASHContext* hash_context_;
+#endif
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SIGNATURE_VERIFIER_H_
diff --git a/libchrome/crypto/signature_verifier_nss.cc b/libchrome/crypto/signature_verifier_nss.cc
new file mode 100644
index 0000000..edbd3f6
--- /dev/null
+++ b/libchrome/crypto/signature_verifier_nss.cc
@@ -0,0 +1,213 @@
+// 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 "crypto/signature_verifier.h"
+
+#include <cryptohi.h>
+#include <keyhi.h>
+#include <pk11pub.h>
+#include <secerr.h>
+#include <sechash.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "crypto/nss_util.h"
+#include "crypto/third_party/nss/chromium-nss.h"
+
+namespace crypto {
+
+namespace {
+
+HASH_HashType ToNSSHashType(SignatureVerifier::HashAlgorithm hash_alg) {
+  switch (hash_alg) {
+    case SignatureVerifier::SHA1:
+      return HASH_AlgSHA1;
+    case SignatureVerifier::SHA256:
+      return HASH_AlgSHA256;
+  }
+  return HASH_AlgNULL;
+}
+
+SECOidTag ToNSSSignatureType(SignatureVerifier::SignatureAlgorithm sig_alg) {
+  switch (sig_alg) {
+    case SignatureVerifier::RSA_PKCS1_SHA1:
+      return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+    case SignatureVerifier::RSA_PKCS1_SHA256:
+      return SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+    case SignatureVerifier::ECDSA_SHA256:
+      return SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
+  }
+  return SEC_OID_UNKNOWN;
+}
+
+SECStatus VerifyRSAPSS_End(SECKEYPublicKey* public_key,
+                           HASHContext* hash_context,
+                           HASH_HashType mask_hash_alg,
+                           unsigned int salt_len,
+                           const unsigned char* signature,
+                           unsigned int signature_len) {
+  unsigned int hash_len = HASH_ResultLenContext(hash_context);
+  std::vector<unsigned char> hash(hash_len);
+  HASH_End(hash_context, &hash[0], &hash_len, hash.size());
+
+  unsigned int modulus_len = SECKEY_PublicKeyStrength(public_key);
+  if (signature_len != modulus_len) {
+    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+    return SECFailure;
+  }
+  std::vector<unsigned char> enc(signature_len);
+  SECStatus rv = PK11_PubEncryptRaw(public_key, &enc[0],
+                                    const_cast<unsigned char*>(signature),
+                                    signature_len, NULL);
+  if (rv != SECSuccess) {
+    LOG(WARNING) << "PK11_PubEncryptRaw failed";
+    return rv;
+  }
+  return emsa_pss_verify(&hash[0], &enc[0], enc.size(),
+                         HASH_GetType(hash_context), mask_hash_alg,
+                         salt_len);
+}
+
+}  // namespace
+
+SignatureVerifier::SignatureVerifier()
+    : vfy_context_(NULL),
+      hash_alg_(SHA1),
+      mask_hash_alg_(SHA1),
+      salt_len_(0),
+      public_key_(NULL),
+      hash_context_(NULL) {
+  EnsureNSSInit();
+}
+
+SignatureVerifier::~SignatureVerifier() {
+  Reset();
+}
+
+bool SignatureVerifier::VerifyInit(SignatureAlgorithm signature_algorithm,
+                                   const uint8_t* signature,
+                                   int signature_len,
+                                   const uint8_t* public_key_info,
+                                   int public_key_info_len) {
+  if (vfy_context_ || hash_context_)
+    return false;
+
+  signature_.assign(signature, signature + signature_len);
+
+  SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info,
+                                                    public_key_info_len);
+  if (!public_key)
+    return false;
+
+  SECItem sig;
+  sig.type = siBuffer;
+  sig.data = const_cast<uint8_t*>(signature);
+  sig.len = signature_len;
+  vfy_context_ = VFY_CreateContext(
+      public_key, &sig, ToNSSSignatureType(signature_algorithm), nullptr);
+  SECKEY_DestroyPublicKey(public_key);  // Done with public_key.
+  if (!vfy_context_) {
+    // A corrupted RSA signature could be detected without the data, so
+    // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE
+    // (-8182).
+    return false;
+  }
+
+  if (VFY_Begin(vfy_context_) != SECSuccess) {
+    NOTREACHED();
+    return false;
+  }
+  return true;
+}
+
+bool SignatureVerifier::VerifyInitRSAPSS(HashAlgorithm hash_alg,
+                                         HashAlgorithm mask_hash_alg,
+                                         int salt_len,
+                                         const uint8_t* signature,
+                                         int signature_len,
+                                         const uint8_t* public_key_info,
+                                         int public_key_info_len) {
+  if (vfy_context_ || hash_context_)
+    return false;
+
+  signature_.assign(signature, signature + signature_len);
+
+  SECKEYPublicKey* public_key = DecodePublicKeyInfo(public_key_info,
+                                                    public_key_info_len);
+  if (!public_key)
+    return false;
+
+  public_key_ = public_key;
+  hash_alg_ = hash_alg;
+  mask_hash_alg_ = mask_hash_alg;
+  salt_len_ = salt_len;
+  hash_context_ = HASH_Create(ToNSSHashType(hash_alg_));
+  if (!hash_context_)
+    return false;
+  HASH_Begin(hash_context_);
+  return true;
+}
+
+void SignatureVerifier::VerifyUpdate(const uint8_t* data_part,
+                                     int data_part_len) {
+  if (vfy_context_) {
+    SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len);
+    DCHECK_EQ(SECSuccess, rv);
+  } else {
+    HASH_Update(hash_context_, data_part, data_part_len);
+  }
+}
+
+bool SignatureVerifier::VerifyFinal() {
+  SECStatus rv;
+  if (vfy_context_) {
+    rv = VFY_End(vfy_context_);
+  } else {
+    rv = VerifyRSAPSS_End(public_key_, hash_context_,
+                          ToNSSHashType(mask_hash_alg_), salt_len_,
+                          signature_.data(),
+                          signature_.size());
+  }
+  Reset();
+
+  // If signature verification fails, the error code is
+  // SEC_ERROR_BAD_SIGNATURE (-8182).
+  return (rv == SECSuccess);
+}
+
+// static
+SECKEYPublicKey* SignatureVerifier::DecodePublicKeyInfo(
+    const uint8_t* public_key_info,
+    int public_key_info_len) {
+  CERTSubjectPublicKeyInfo* spki = NULL;
+  SECItem spki_der;
+  spki_der.type = siBuffer;
+  spki_der.data = const_cast<uint8_t*>(public_key_info);
+  spki_der.len = public_key_info_len;
+  spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der);
+  if (!spki)
+    return NULL;
+  SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
+  SECKEY_DestroySubjectPublicKeyInfo(spki);  // Done with spki.
+  return public_key;
+}
+
+void SignatureVerifier::Reset() {
+  if (vfy_context_) {
+    VFY_DestroyContext(vfy_context_, PR_TRUE);
+    vfy_context_ = NULL;
+  }
+  if (hash_context_) {
+    HASH_Destroy(hash_context_);
+    hash_context_ = NULL;
+  }
+  if (public_key_) {
+    SECKEY_DestroyPublicKey(public_key_);
+    public_key_ = NULL;
+  }
+  signature_.clear();
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/signature_verifier_unittest.cc b/libchrome/crypto/signature_verifier_unittest.cc
new file mode 100644
index 0000000..d71ea82
--- /dev/null
+++ b/libchrome/crypto/signature_verifier_unittest.cc
@@ -0,0 +1,1144 @@
+// 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 "crypto/signature_verifier.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SignatureVerifierTest, BasicTest) {
+  // The input data in this test comes from real certificates.
+  //
+  // tbs_certificate ("to-be-signed certificate", the part of a certificate that
+  // is signed), signature, and algorithm come from the certificate of
+  // bugs.webkit.org.
+  //
+  // public_key_info comes from the certificate of the issuer, Go Daddy Secure
+  // Certification Authority.
+  //
+  // The bytes in the array initializers are formatted to expose the DER
+  // encoding of the ASN.1 structures.
+
+  // The data that is signed is the following ASN.1 structure:
+  //    TBSCertificate  ::=  SEQUENCE  {
+  //        ...  -- omitted, not important
+  //        }
+  const uint8_t tbs_certificate[1017] = {
+      0x30, 0x82, 0x03, 0xf5,  // a SEQUENCE of length 1013 (0x3f5)
+      0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x43, 0xdd, 0x63, 0x30, 0x0d,
+      0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+      0x00, 0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+      0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+      0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31,
+      0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63,
+      0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18,
+      0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64,
+      0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+      0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68,
+      0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
+      0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
+      0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
+      0x69, 0x74, 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55,
+      0x04, 0x03, 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79,
+      0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74,
+      0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+      0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06,
+      0x03, 0x55, 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32,
+      0x38, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x31, 0x38,
+      0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
+      0x33, 0x31, 0x38, 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x30, 0x79,
+      0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+      0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
+      0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12,
+      0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x75, 0x70,
+      0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+      0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49,
+      0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b,
+      0x13, 0x0c, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x46, 0x6f, 0x72,
+      0x67, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+      0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72,
+      0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+      0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
+      0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa7, 0x62, 0x79, 0x41, 0xda, 0x28,
+      0xf2, 0xc0, 0x4f, 0xe0, 0x25, 0xaa, 0xa1, 0x2e, 0x3b, 0x30, 0x94, 0xb5,
+      0xc9, 0x26, 0x3a, 0x1b, 0xe2, 0xd0, 0xcc, 0xa2, 0x95, 0xe2, 0x91, 0xc0,
+      0xf0, 0x40, 0x9e, 0x27, 0x6e, 0xbd, 0x6e, 0xde, 0x7c, 0xb6, 0x30, 0x5c,
+      0xb8, 0x9b, 0x01, 0x2f, 0x92, 0x04, 0xa1, 0xef, 0x4a, 0xb1, 0x6c, 0xb1,
+      0x7e, 0x8e, 0xcd, 0xa6, 0xf4, 0x40, 0x73, 0x1f, 0x2c, 0x96, 0xad, 0xff,
+      0x2a, 0x6d, 0x0e, 0xba, 0x52, 0x84, 0x83, 0xb0, 0x39, 0xee, 0xc9, 0x39,
+      0xdc, 0x1e, 0x34, 0xd0, 0xd8, 0x5d, 0x7a, 0x09, 0xac, 0xa9, 0xee, 0xca,
+      0x65, 0xf6, 0x85, 0x3a, 0x6b, 0xee, 0xe4, 0x5c, 0x5e, 0xf8, 0xda, 0xd1,
+      0xce, 0x88, 0x47, 0xcd, 0x06, 0x21, 0xe0, 0xb9, 0x4b, 0xe4, 0x07, 0xcb,
+      0x57, 0xdc, 0xca, 0x99, 0x54, 0xf7, 0x0e, 0xd5, 0x17, 0x95, 0x05, 0x2e,
+      0xe9, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xce, 0x30,
+      0x82, 0x01, 0xca, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02,
+      0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03,
+      0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16,
+      0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01,
+      0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x57,
+      0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x50, 0x30, 0x4e, 0x30, 0x4c, 0xa0,
+      0x4a, 0xa0, 0x48, 0x86, 0x46, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+      0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73,
+      0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
+      0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f,
+      0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x65, 0x78, 0x74, 0x65, 0x6e,
+      0x64, 0x65, 0x64, 0x69, 0x73, 0x73, 0x75, 0x69, 0x6e, 0x67, 0x33, 0x2e,
+      0x63, 0x72, 0x6c, 0x30, 0x52, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4b,
+      0x30, 0x49, 0x30, 0x47, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd,
+      0x6d, 0x01, 0x07, 0x17, 0x02, 0x30, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b,
+      0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2a, 0x68, 0x74, 0x74,
+      0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+      0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
+      0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
+      0x6f, 0x72, 0x79, 0x30, 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+      0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x23, 0x06, 0x08, 0x2b,
+      0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74,
+      0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
+      0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4a, 0x06, 0x08,
+      0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74,
+      0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+      0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64,
+      0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69,
+      0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65,
+      0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x74,
+      0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48,
+      0xdf, 0x60, 0x32, 0xcc, 0x89, 0x01, 0xb6, 0xdc, 0x2f, 0xe3, 0x73, 0xb5,
+      0x9c, 0x16, 0x58, 0x32, 0x68, 0xa9, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55,
+      0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32,
+      0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee, 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76,
+      0x99, 0x68, 0xcc, 0xe7, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04,
+      0x1c, 0x30, 0x1a, 0x82, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69,
+      0x74, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x0a, 0x77, 0x65, 0x62, 0x6b, 0x69,
+      0x74, 0x2e, 0x6f, 0x72, 0x67};
+
+  // RSA signature, a big integer in the big-endian byte order.
+  const uint8_t signature[256] = {
+      0x1e, 0x6a, 0xe7, 0xe0, 0x4f, 0xe7, 0x4d, 0xd0, 0x69, 0x7c, 0xf8, 0x8f,
+      0x99, 0xb4, 0x18, 0x95, 0x36, 0x24, 0x0f, 0x0e, 0xa3, 0xea, 0x34, 0x37,
+      0xf4, 0x7d, 0xd5, 0x92, 0x35, 0x53, 0x72, 0x76, 0x3f, 0x69, 0xf0, 0x82,
+      0x56, 0xe3, 0x94, 0x7a, 0x1d, 0x1a, 0x81, 0xaf, 0x9f, 0xc7, 0x43, 0x01,
+      0x64, 0xd3, 0x7c, 0x0d, 0xc8, 0x11, 0x4e, 0x4a, 0xe6, 0x1a, 0xc3, 0x01,
+      0x74, 0xe8, 0x35, 0x87, 0x5c, 0x61, 0xaa, 0x8a, 0x46, 0x06, 0xbe, 0x98,
+      0x95, 0x24, 0x9e, 0x01, 0xe3, 0xe6, 0xa0, 0x98, 0xee, 0x36, 0x44, 0x56,
+      0x8d, 0x23, 0x9c, 0x65, 0xea, 0x55, 0x6a, 0xdf, 0x66, 0xee, 0x45, 0xe8,
+      0xa0, 0xe9, 0x7d, 0x9a, 0xba, 0x94, 0xc5, 0xc8, 0xc4, 0x4b, 0x98, 0xff,
+      0x9a, 0x01, 0x31, 0x6d, 0xf9, 0x2b, 0x58, 0xe7, 0xe7, 0x2a, 0xc5, 0x4d,
+      0xbb, 0xbb, 0xcd, 0x0d, 0x70, 0xe1, 0xad, 0x03, 0xf5, 0xfe, 0xf4, 0x84,
+      0x71, 0x08, 0xd2, 0xbc, 0x04, 0x7b, 0x26, 0x1c, 0xa8, 0x0f, 0x9c, 0xd8,
+      0x12, 0x6a, 0x6f, 0x2b, 0x67, 0xa1, 0x03, 0x80, 0x9a, 0x11, 0x0b, 0xe9,
+      0xe0, 0xb5, 0xb3, 0xb8, 0x19, 0x4e, 0x0c, 0xa4, 0xd9, 0x2b, 0x3b, 0xc2,
+      0xca, 0x20, 0xd3, 0x0c, 0xa4, 0xff, 0x93, 0x13, 0x1f, 0xfc, 0xba, 0x94,
+      0x93, 0x8c, 0x64, 0x15, 0x2e, 0x28, 0xa9, 0x55, 0x8c, 0x2c, 0x48, 0xd3,
+      0xd3, 0xc1, 0x50, 0x69, 0x19, 0xe8, 0x34, 0xd3, 0xf1, 0x04, 0x9f, 0x0a,
+      0x7a, 0x21, 0x87, 0xbf, 0xb9, 0x59, 0x37, 0x2e, 0xf4, 0x71, 0xa5, 0x3e,
+      0xbe, 0xcd, 0x70, 0x83, 0x18, 0xf8, 0x8a, 0x72, 0x85, 0x45, 0x1f, 0x08,
+      0x01, 0x6f, 0x37, 0xf5, 0x2b, 0x7b, 0xea, 0xb9, 0x8b, 0xa3, 0xcc, 0xfd,
+      0x35, 0x52, 0xdd, 0x66, 0xde, 0x4f, 0x30, 0xc5, 0x73, 0x81, 0xb6, 0xe8,
+      0x3c, 0xd8, 0x48, 0x8a};
+
+  // The public key is specified as the following ASN.1 structure:
+  //   SubjectPublicKeyInfo  ::=  SEQUENCE  {
+  //       algorithm            AlgorithmIdentifier,
+  //       subjectPublicKey     BIT STRING  }
+  const uint8_t public_key_info[294] = {
+      0x30, 0x82, 0x01, 0x22,  // a SEQUENCE of length 290 (0x122)
+      // algorithm
+      0x30, 0x0d,  // a SEQUENCE of length 13
+      0x06, 0x09,  // an OBJECT IDENTIFIER of length 9
+      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+      0x00,  // a NULL of length 0
+      // subjectPublicKey
+      0x03, 0x82, 0x01, 0x0f,  // a BIT STRING of length 271 (0x10f)
+      0x00,                    // number of unused bits
+      0x30, 0x82, 0x01, 0x0a,  // a SEQUENCE of length 266 (0x10a)
+      // modulus
+      0x02, 0x82, 0x01, 0x01,  // an INTEGER of length 257 (0x101)
+      0x00, 0xc4, 0x2d, 0xd5, 0x15, 0x8c, 0x9c, 0x26, 0x4c, 0xec, 0x32, 0x35,
+      0xeb, 0x5f, 0xb8, 0x59, 0x01, 0x5a, 0xa6, 0x61, 0x81, 0x59, 0x3b, 0x70,
+      0x63, 0xab, 0xe3, 0xdc, 0x3d, 0xc7, 0x2a, 0xb8, 0xc9, 0x33, 0xd3, 0x79,
+      0xe4, 0x3a, 0xed, 0x3c, 0x30, 0x23, 0x84, 0x8e, 0xb3, 0x30, 0x14, 0xb6,
+      0xb2, 0x87, 0xc3, 0x3d, 0x95, 0x54, 0x04, 0x9e, 0xdf, 0x99, 0xdd, 0x0b,
+      0x25, 0x1e, 0x21, 0xde, 0x65, 0x29, 0x7e, 0x35, 0xa8, 0xa9, 0x54, 0xeb,
+      0xf6, 0xf7, 0x32, 0x39, 0xd4, 0x26, 0x55, 0x95, 0xad, 0xef, 0xfb, 0xfe,
+      0x58, 0x86, 0xd7, 0x9e, 0xf4, 0x00, 0x8d, 0x8c, 0x2a, 0x0c, 0xbd, 0x42,
+      0x04, 0xce, 0xa7, 0x3f, 0x04, 0xf6, 0xee, 0x80, 0xf2, 0xaa, 0xef, 0x52,
+      0xa1, 0x69, 0x66, 0xda, 0xbe, 0x1a, 0xad, 0x5d, 0xda, 0x2c, 0x66, 0xea,
+      0x1a, 0x6b, 0xbb, 0xe5, 0x1a, 0x51, 0x4a, 0x00, 0x2f, 0x48, 0xc7, 0x98,
+      0x75, 0xd8, 0xb9, 0x29, 0xc8, 0xee, 0xf8, 0x66, 0x6d, 0x0a, 0x9c, 0xb3,
+      0xf3, 0xfc, 0x78, 0x7c, 0xa2, 0xf8, 0xa3, 0xf2, 0xb5, 0xc3, 0xf3, 0xb9,
+      0x7a, 0x91, 0xc1, 0xa7, 0xe6, 0x25, 0x2e, 0x9c, 0xa8, 0xed, 0x12, 0x65,
+      0x6e, 0x6a, 0xf6, 0x12, 0x44, 0x53, 0x70, 0x30, 0x95, 0xc3, 0x9c, 0x2b,
+      0x58, 0x2b, 0x3d, 0x08, 0x74, 0x4a, 0xf2, 0xbe, 0x51, 0xb0, 0xbf, 0x87,
+      0xd0, 0x4c, 0x27, 0x58, 0x6b, 0xb5, 0x35, 0xc5, 0x9d, 0xaf, 0x17, 0x31,
+      0xf8, 0x0b, 0x8f, 0xee, 0xad, 0x81, 0x36, 0x05, 0x89, 0x08, 0x98, 0xcf,
+      0x3a, 0xaf, 0x25, 0x87, 0xc0, 0x49, 0xea, 0xa7, 0xfd, 0x67, 0xf7, 0x45,
+      0x8e, 0x97, 0xcc, 0x14, 0x39, 0xe2, 0x36, 0x85, 0xb5, 0x7e, 0x1a, 0x37,
+      0xfd, 0x16, 0xf6, 0x71, 0x11, 0x9a, 0x74, 0x30, 0x16, 0xfe, 0x13, 0x94,
+      0xa3, 0x3f, 0x84, 0x0d, 0x4f,
+      // public exponent
+      0x02, 0x03,  // an INTEGER of length 3
+      0x01, 0x00, 0x01};
+
+  // We use the signature verifier to perform four signature verification
+  // tests.
+  crypto::SignatureVerifier verifier;
+  bool ok;
+
+  // Test  1: feed all of the data to the verifier at once (a single
+  // VerifyUpdate call).
+  ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+                           sizeof(signature), public_key_info,
+                           sizeof(public_key_info));
+  EXPECT_TRUE(ok);
+  verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate));
+  ok = verifier.VerifyFinal();
+  EXPECT_TRUE(ok);
+
+  // Test 2: feed the data to the verifier in three parts (three VerifyUpdate
+  // calls).
+  ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+                           sizeof(signature), public_key_info,
+                           sizeof(public_key_info));
+  EXPECT_TRUE(ok);
+  verifier.VerifyUpdate(tbs_certificate, 256);
+  verifier.VerifyUpdate(tbs_certificate + 256, 256);
+  verifier.VerifyUpdate(tbs_certificate + 512, sizeof(tbs_certificate) - 512);
+  ok = verifier.VerifyFinal();
+  EXPECT_TRUE(ok);
+
+  // Test 3: verify the signature with incorrect data.
+  uint8_t bad_tbs_certificate[sizeof(tbs_certificate)];
+  memcpy(bad_tbs_certificate, tbs_certificate, sizeof(tbs_certificate));
+  bad_tbs_certificate[10] += 1;  // Corrupt one byte of the data.
+  ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+                           sizeof(signature), public_key_info,
+                           sizeof(public_key_info));
+  EXPECT_TRUE(ok);
+  verifier.VerifyUpdate(bad_tbs_certificate, sizeof(bad_tbs_certificate));
+  ok = verifier.VerifyFinal();
+  EXPECT_FALSE(ok);
+
+  // Test 4: verify a bad signature.
+  uint8_t bad_signature[sizeof(signature)];
+  memcpy(bad_signature, signature, sizeof(signature));
+  bad_signature[10] += 1;  // Corrupt one byte of the signature.
+  ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1,
+                           bad_signature, sizeof(bad_signature),
+                           public_key_info, sizeof(public_key_info));
+
+  // A crypto library (e.g., NSS) may detect that the signature is corrupted
+  // and cause VerifyInit to return false, so it is fine for 'ok' to be false.
+  if (ok) {
+    verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate));
+    ok = verifier.VerifyFinal();
+    EXPECT_FALSE(ok);
+  }
+
+  // Test 5: import an invalid key.
+  uint8_t bad_public_key_info[sizeof(public_key_info)];
+  memcpy(bad_public_key_info, public_key_info, sizeof(public_key_info));
+  bad_public_key_info[0] += 1;  // Corrupt part of the SPKI syntax.
+  ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+                           sizeof(signature), bad_public_key_info,
+                           sizeof(bad_public_key_info));
+  EXPECT_FALSE(ok);
+
+  // Test 6: import a key with extra data.
+  uint8_t long_public_key_info[sizeof(public_key_info) + 5];
+  memset(long_public_key_info, 0, sizeof(long_public_key_info));
+  memcpy(long_public_key_info, public_key_info, sizeof(public_key_info));
+  ok = verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, signature,
+                           sizeof(signature), long_public_key_info,
+                           sizeof(long_public_key_info));
+  EXPECT_FALSE(ok);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// RSA-PSS signature verification known answer test
+//
+//////////////////////////////////////////////////////////////////////
+
+// The following RSA-PSS signature test vectors come from the pss-vect.txt
+// file downloaded from
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip.
+//
+// For each key, 6 random messages of length between 1 and 256 octets have
+// been RSASSA-PSS signed.
+//
+// Hash function: SHA-1
+// Mask generation function: MGF1 with SHA-1
+// Salt length: 20 octets
+
+// Example 1: A 1024-bit RSA Key Pair"
+
+// RSA modulus n:
+static const char rsa_modulus_n_1[] =
+  "a5 6e 4a 0e 70 10 17 58 9a 51 87 dc 7e a8 41 d1 "
+  "56 f2 ec 0e 36 ad 52 a4 4d fe b1 e6 1f 7a d9 91 "
+  "d8 c5 10 56 ff ed b1 62 b4 c0 f2 83 a1 2a 88 a3 "
+  "94 df f5 26 ab 72 91 cb b3 07 ce ab fc e0 b1 df "
+  "d5 cd 95 08 09 6d 5b 2b 8b 6d f5 d6 71 ef 63 77 "
+  "c0 92 1c b2 3c 27 0a 70 e2 59 8e 6f f8 9d 19 f1 "
+  "05 ac c2 d3 f0 cb 35 f2 92 80 e1 38 6b 6f 64 c4 "
+  "ef 22 e1 e1 f2 0d 0c e8 cf fb 22 49 bd 9a 21 37 ";
+// RSA public exponent e: "
+static const char rsa_public_exponent_e_1[] =
+  "01 00 01 ";
+
+// RSASSA-PSS Signature Example 1.1
+// Message to be signed:
+static const char message_1_1[] =
+  "cd c8 7d a2 23 d7 86 df 3b 45 e0 bb bc 72 13 26 "
+  "d1 ee 2a f8 06 cc 31 54 75 cc 6f 0d 9c 66 e1 b6 "
+  "23 71 d4 5c e2 39 2e 1a c9 28 44 c3 10 10 2f 15 "
+  "6a 0d 8d 52 c1 f4 c4 0b a3 aa 65 09 57 86 cb 76 "
+  "97 57 a6 56 3b a9 58 fe d0 bc c9 84 e8 b5 17 a3 "
+  "d5 f5 15 b2 3b 8a 41 e7 4a a8 67 69 3f 90 df b0 "
+  "61 a6 e8 6d fa ae e6 44 72 c0 0e 5f 20 94 57 29 "
+  "cb eb e7 7f 06 ce 78 e0 8f 40 98 fb a4 1f 9d 61 "
+  "93 c0 31 7e 8b 60 d4 b6 08 4a cb 42 d2 9e 38 08 "
+  "a3 bc 37 2d 85 e3 31 17 0f cb f7 cc 72 d0 b7 1c "
+  "29 66 48 b3 a4 d1 0f 41 62 95 d0 80 7a a6 25 ca "
+  "b2 74 4f d9 ea 8f d2 23 c4 25 37 02 98 28 bd 16 "
+  "be 02 54 6f 13 0f d2 e3 3b 93 6d 26 76 e0 8a ed "
+  "1b 73 31 8b 75 0a 01 67 d0 ";
+// Salt:
+static const char salt_1_1[] =
+  "de e9 59 c7 e0 64 11 36 14 20 ff 80 18 5e d5 7f "
+  "3e 67 76 af ";
+// Signature:
+static const char signature_1_1[] =
+  "90 74 30 8f b5 98 e9 70 1b 22 94 38 8e 52 f9 71 "
+  "fa ac 2b 60 a5 14 5a f1 85 df 52 87 b5 ed 28 87 "
+  "e5 7c e7 fd 44 dc 86 34 e4 07 c8 e0 e4 36 0b c2 "
+  "26 f3 ec 22 7f 9d 9e 54 63 8e 8d 31 f5 05 12 15 "
+  "df 6e bb 9c 2f 95 79 aa 77 59 8a 38 f9 14 b5 b9 "
+  "c1 bd 83 c4 e2 f9 f3 82 a0 d0 aa 35 42 ff ee 65 "
+  "98 4a 60 1b c6 9e b2 8d eb 27 dc a1 2c 82 c2 d4 "
+  "c3 f6 6c d5 00 f1 ff 2b 99 4d 8a 4e 30 cb b3 3c ";
+
+// RSASSA-PSS Signature Example 1.2
+// Message to be signed:
+static const char message_1_2[] =
+  "85 13 84 cd fe 81 9c 22 ed 6c 4c cb 30 da eb 5c "
+  "f0 59 bc 8e 11 66 b7 e3 53 0c 4c 23 3e 2b 5f 8f "
+  "71 a1 cc a5 82 d4 3e cc 72 b1 bc a1 6d fc 70 13 "
+  "22 6b 9e ";
+// Salt:
+static const char salt_1_2[] =
+  "ef 28 69 fa 40 c3 46 cb 18 3d ab 3d 7b ff c9 8f "
+  "d5 6d f4 2d ";
+// Signature:
+static const char signature_1_2[] =
+  "3e f7 f4 6e 83 1b f9 2b 32 27 41 42 a5 85 ff ce "
+  "fb dc a7 b3 2a e9 0d 10 fb 0f 0c 72 99 84 f0 4e "
+  "f2 9a 9d f0 78 07 75 ce 43 73 9b 97 83 83 90 db "
+  "0a 55 05 e6 3d e9 27 02 8d 9d 29 b2 19 ca 2c 45 "
+  "17 83 25 58 a5 5d 69 4a 6d 25 b9 da b6 60 03 c4 "
+  "cc cd 90 78 02 19 3b e5 17 0d 26 14 7d 37 b9 35 "
+  "90 24 1b e5 1c 25 05 5f 47 ef 62 75 2c fb e2 14 "
+  "18 fa fe 98 c2 2c 4d 4d 47 72 4f db 56 69 e8 43 ";
+
+// RSASSA-PSS Signature Example 1.3
+// Message to be signed:
+static const char message_1_3[] =
+  "a4 b1 59 94 17 61 c4 0c 6a 82 f2 b8 0d 1b 94 f5 "
+  "aa 26 54 fd 17 e1 2d 58 88 64 67 9b 54 cd 04 ef "
+  "8b d0 30 12 be 8d c3 7f 4b 83 af 79 63 fa ff 0d "
+  "fa 22 54 77 43 7c 48 01 7f f2 be 81 91 cf 39 55 "
+  "fc 07 35 6e ab 3f 32 2f 7f 62 0e 21 d2 54 e5 db "
+  "43 24 27 9f e0 67 e0 91 0e 2e 81 ca 2c ab 31 c7 "
+  "45 e6 7a 54 05 8e b5 0d 99 3c db 9e d0 b4 d0 29 "
+  "c0 6d 21 a9 4c a6 61 c3 ce 27 fa e1 d6 cb 20 f4 "
+  "56 4d 66 ce 47 67 58 3d 0e 5f 06 02 15 b5 90 17 "
+  "be 85 ea 84 89 39 12 7b d8 c9 c4 d4 7b 51 05 6c "
+  "03 1c f3 36 f1 7c 99 80 f3 b8 f5 b9 b6 87 8e 8b "
+  "79 7a a4 3b 88 26 84 33 3e 17 89 3f e9 ca a6 aa "
+  "29 9f 7e d1 a1 8e e2 c5 48 64 b7 b2 b9 9b 72 61 "
+  "8f b0 25 74 d1 39 ef 50 f0 19 c9 ee f4 16 97 13 "
+  "38 e7 d4 70 ";
+// Salt:
+static const char salt_1_3[] =
+  "71 0b 9c 47 47 d8 00 d4 de 87 f1 2a fd ce 6d f1 "
+  "81 07 cc 77 ";
+// Signature:
+static const char signature_1_3[] =
+  "66 60 26 fb a7 1b d3 e7 cf 13 15 7c c2 c5 1a 8e "
+  "4a a6 84 af 97 78 f9 18 49 f3 43 35 d1 41 c0 01 "
+  "54 c4 19 76 21 f9 62 4a 67 5b 5a bc 22 ee 7d 5b "
+  "aa ff aa e1 c9 ba ca 2c c3 73 b3 f3 3e 78 e6 14 "
+  "3c 39 5a 91 aa 7f ac a6 64 eb 73 3a fd 14 d8 82 "
+  "72 59 d9 9a 75 50 fa ca 50 1e f2 b0 4e 33 c2 3a "
+  "a5 1f 4b 9e 82 82 ef db 72 8c c0 ab 09 40 5a 91 "
+  "60 7c 63 69 96 1b c8 27 0d 2d 4f 39 fc e6 12 b1 ";
+
+// RSASSA-PSS Signature Example 1.4
+// Message to be signed:
+static const char message_1_4[] =
+  "bc 65 67 47 fa 9e af b3 f0 ";
+// Salt:
+static const char salt_1_4[] =
+  "05 6f 00 98 5d e1 4d 8e f5 ce a9 e8 2f 8c 27 be "
+  "f7 20 33 5e ";
+// Signature:
+static const char signature_1_4[] =
+  "46 09 79 3b 23 e9 d0 93 62 dc 21 bb 47 da 0b 4f "
+  "3a 76 22 64 9a 47 d4 64 01 9b 9a ea fe 53 35 9c "
+  "17 8c 91 cd 58 ba 6b cb 78 be 03 46 a7 bc 63 7f "
+  "4b 87 3d 4b ab 38 ee 66 1f 19 96 34 c5 47 a1 ad "
+  "84 42 e0 3d a0 15 b1 36 e5 43 f7 ab 07 c0 c1 3e "
+  "42 25 b8 de 8c ce 25 d4 f6 eb 84 00 f8 1f 7e 18 "
+  "33 b7 ee 6e 33 4d 37 09 64 ca 79 fd b8 72 b4 d7 "
+  "52 23 b5 ee b0 81 01 59 1f b5 32 d1 55 a6 de 87 ";
+
+// RSASSA-PSS Signature Example 1.5
+// Message to be signed:
+static const char message_1_5[] =
+  "b4 55 81 54 7e 54 27 77 0c 76 8e 8b 82 b7 55 64 "
+  "e0 ea 4e 9c 32 59 4d 6b ff 70 65 44 de 0a 87 76 "
+  "c7 a8 0b 45 76 55 0e ee 1b 2a ca bc 7e 8b 7d 3e "
+  "f7 bb 5b 03 e4 62 c1 10 47 ea dd 00 62 9a e5 75 "
+  "48 0a c1 47 0f e0 46 f1 3a 2b f5 af 17 92 1d c4 "
+  "b0 aa 8b 02 be e6 33 49 11 65 1d 7f 85 25 d1 0f "
+  "32 b5 1d 33 be 52 0d 3d df 5a 70 99 55 a3 df e7 "
+  "82 83 b9 e0 ab 54 04 6d 15 0c 17 7f 03 7f dc cc "
+  "5b e4 ea 5f 68 b5 e5 a3 8c 9d 7e dc cc c4 97 5f "
+  "45 5a 69 09 b4 ";
+// Salt:
+static const char salt_1_5[] =
+  "80 e7 0f f8 6a 08 de 3e c6 09 72 b3 9b 4f bf dc "
+  "ea 67 ae 8e ";
+// Signature:
+static const char signature_1_5[] =
+  "1d 2a ad 22 1c a4 d3 1d df 13 50 92 39 01 93 98 "
+  "e3 d1 4b 32 dc 34 dc 5a f4 ae ae a3 c0 95 af 73 "
+  "47 9c f0 a4 5e 56 29 63 5a 53 a0 18 37 76 15 b1 "
+  "6c b9 b1 3b 3e 09 d6 71 eb 71 e3 87 b8 54 5c 59 "
+  "60 da 5a 64 77 6e 76 8e 82 b2 c9 35 83 bf 10 4c "
+  "3f db 23 51 2b 7b 4e 89 f6 33 dd 00 63 a5 30 db "
+  "45 24 b0 1c 3f 38 4c 09 31 0e 31 5a 79 dc d3 d6 "
+  "84 02 2a 7f 31 c8 65 a6 64 e3 16 97 8b 75 9f ad ";
+
+// RSASSA-PSS Signature Example 1.6
+// Message to be signed:
+static const char message_1_6[] =
+  "10 aa e9 a0 ab 0b 59 5d 08 41 20 7b 70 0d 48 d7 "
+  "5f ae dd e3 b7 75 cd 6b 4c c8 8a e0 6e 46 94 ec "
+  "74 ba 18 f8 52 0d 4f 5e a6 9c bb e7 cc 2b eb a4 "
+  "3e fd c1 02 15 ac 4e b3 2d c3 02 a1 f5 3d c6 c4 "
+  "35 22 67 e7 93 6c fe bf 7c 8d 67 03 57 84 a3 90 "
+  "9f a8 59 c7 b7 b5 9b 8e 39 c5 c2 34 9f 18 86 b7 "
+  "05 a3 02 67 d4 02 f7 48 6a b4 f5 8c ad 5d 69 ad "
+  "b1 7a b8 cd 0c e1 ca f5 02 5a f4 ae 24 b1 fb 87 "
+  "94 c6 07 0c c0 9a 51 e2 f9 91 13 11 e3 87 7d 00 "
+  "44 c7 1c 57 a9 93 39 50 08 80 6b 72 3a c3 83 73 "
+  "d3 95 48 18 18 52 8c 1e 70 53 73 92 82 05 35 29 "
+  "51 0e 93 5c d0 fa 77 b8 fa 53 cc 2d 47 4b d4 fb "
+  "3c c5 c6 72 d6 ff dc 90 a0 0f 98 48 71 2c 4b cf "
+  "e4 6c 60 57 36 59 b1 1e 64 57 e8 61 f0 f6 04 b6 "
+  "13 8d 14 4f 8c e4 e2 da 73 ";
+// Salt:
+static const char salt_1_6[] =
+  "a8 ab 69 dd 80 1f 00 74 c2 a1 fc 60 64 98 36 c6 "
+  "16 d9 96 81 ";
+// Signature:
+static const char signature_1_6[] =
+  "2a 34 f6 12 5e 1f 6b 0b f9 71 e8 4f bd 41 c6 32 "
+  "be 8f 2c 2a ce 7d e8 b6 92 6e 31 ff 93 e9 af 98 "
+  "7f bc 06 e5 1e 9b e1 4f 51 98 f9 1f 3f 95 3b d6 "
+  "7d a6 0a 9d f5 97 64 c3 dc 0f e0 8e 1c be f0 b7 "
+  "5f 86 8d 10 ad 3f ba 74 9f ef 59 fb 6d ac 46 a0 "
+  "d6 e5 04 36 93 31 58 6f 58 e4 62 8f 39 aa 27 89 "
+  "82 54 3b c0 ee b5 37 dc 61 95 80 19 b3 94 fb 27 "
+  "3f 21 58 58 a0 a0 1a c4 d6 50 b9 55 c6 7f 4c 58 ";
+
+// Example 9: A 1536-bit RSA Key Pair
+
+// RSA modulus n:
+static const char rsa_modulus_n_9[] =
+  "e6 bd 69 2a c9 66 45 79 04 03 fd d0 f5 be b8 b9 "
+  "bf 92 ed 10 00 7f c3 65 04 64 19 dd 06 c0 5c 5b "
+  "5b 2f 48 ec f9 89 e4 ce 26 91 09 97 9c bb 40 b4 "
+  "a0 ad 24 d2 24 83 d1 ee 31 5a d4 cc b1 53 42 68 "
+  "35 26 91 c5 24 f6 dd 8e 6c 29 d2 24 cf 24 69 73 "
+  "ae c8 6c 5b f6 b1 40 1a 85 0d 1b 9a d1 bb 8c bc "
+  "ec 47 b0 6f 0f 8c 7f 45 d3 fc 8f 31 92 99 c5 43 "
+  "3d db c2 b3 05 3b 47 de d2 ec d4 a4 ca ef d6 14 "
+  "83 3d c8 bb 62 2f 31 7e d0 76 b8 05 7f e8 de 3f "
+  "84 48 0a d5 e8 3e 4a 61 90 4a 4f 24 8f b3 97 02 "
+  "73 57 e1 d3 0e 46 31 39 81 5c 6f d4 fd 5a c5 b8 "
+  "17 2a 45 23 0e cb 63 18 a0 4f 14 55 d8 4e 5a 8b ";
+// RSA public exponent e:
+static const char rsa_public_exponent_e_9[] =
+  "01 00 01 ";
+
+// RSASSA-PSS Signature Example 9.1
+// Message to be signed:
+static const char message_9_1[] =
+  "a8 8e 26 58 55 e9 d7 ca 36 c6 87 95 f0 b3 1b 59 "
+  "1c d6 58 7c 71 d0 60 a0 b3 f7 f3 ea ef 43 79 59 "
+  "22 02 8b c2 b6 ad 46 7c fc 2d 7f 65 9c 53 85 aa "
+  "70 ba 36 72 cd de 4c fe 49 70 cc 79 04 60 1b 27 "
+  "88 72 bf 51 32 1c 4a 97 2f 3c 95 57 0f 34 45 d4 "
+  "f5 79 80 e0 f2 0d f5 48 46 e6 a5 2c 66 8f 12 88 "
+  "c0 3f 95 00 6e a3 2f 56 2d 40 d5 2a f9 fe b3 2f "
+  "0f a0 6d b6 5b 58 8a 23 7b 34 e5 92 d5 5c f9 79 "
+  "f9 03 a6 42 ef 64 d2 ed 54 2a a8 c7 7d c1 dd 76 "
+  "2f 45 a5 93 03 ed 75 e5 41 ca 27 1e 2b 60 ca 70 "
+  "9e 44 fa 06 61 13 1e 8d 5d 41 63 fd 8d 39 85 66 "
+  "ce 26 de 87 30 e7 2f 9c ca 73 76 41 c2 44 15 94 "
+  "20 63 70 28 df 0a 18 07 9d 62 08 ea 8b 47 11 a2 "
+  "c7 50 f5 ";
+// Salt:
+static const char salt_9_1[] =
+  "c0 a4 25 31 3d f8 d7 56 4b d2 43 4d 31 15 23 d5 "
+  "25 7e ed 80 ";
+// Signature:
+static const char signature_9_1[] =
+  "58 61 07 22 6c 3c e0 13 a7 c8 f0 4d 1a 6a 29 59 "
+  "bb 4b 8e 20 5b a4 3a 27 b5 0f 12 41 11 bc 35 ef "
+  "58 9b 03 9f 59 32 18 7c b6 96 d7 d9 a3 2c 0c 38 "
+  "30 0a 5c dd a4 83 4b 62 d2 eb 24 0a f3 3f 79 d1 "
+  "3d fb f0 95 bf 59 9e 0d 96 86 94 8c 19 64 74 7b "
+  "67 e8 9c 9a ba 5c d8 50 16 23 6f 56 6c c5 80 2c "
+  "b1 3e ad 51 bc 7c a6 be f3 b9 4d cb db b1 d5 70 "
+  "46 97 71 df 0e 00 b1 a8 a0 67 77 47 2d 23 16 27 "
+  "9e da e8 64 74 66 8d 4e 1e ff f9 5f 1d e6 1c 60 "
+  "20 da 32 ae 92 bb f1 65 20 fe f3 cf 4d 88 f6 11 "
+  "21 f2 4b bd 9f e9 1b 59 ca f1 23 5b 2a 93 ff 81 "
+  "fc 40 3a dd f4 eb de a8 49 34 a9 cd af 8e 1a 9e ";
+
+// RSASSA-PSS Signature Example 9.2
+// Message to be signed:
+static const char message_9_2[] =
+  "c8 c9 c6 af 04 ac da 41 4d 22 7e f2 3e 08 20 c3 "
+  "73 2c 50 0d c8 72 75 e9 5b 0d 09 54 13 99 3c 26 "
+  "58 bc 1d 98 85 81 ba 87 9c 2d 20 1f 14 cb 88 ce "
+  "d1 53 a0 19 69 a7 bf 0a 7b e7 9c 84 c1 48 6b c1 "
+  "2b 3f a6 c5 98 71 b6 82 7c 8c e2 53 ca 5f ef a8 "
+  "a8 c6 90 bf 32 6e 8e 37 cd b9 6d 90 a8 2e ba b6 "
+  "9f 86 35 0e 18 22 e8 bd 53 6a 2e ";
+// Salt:
+static const char salt_9_2[] =
+  "b3 07 c4 3b 48 50 a8 da c2 f1 5f 32 e3 78 39 ef "
+  "8c 5c 0e 91 ";
+// Signature:
+static const char signature_9_2[] =
+  "80 b6 d6 43 25 52 09 f0 a4 56 76 38 97 ac 9e d2 "
+  "59 d4 59 b4 9c 28 87 e5 88 2e cb 44 34 cf d6 6d "
+  "d7 e1 69 93 75 38 1e 51 cd 7f 55 4f 2c 27 17 04 "
+  "b3 99 d4 2b 4b e2 54 0a 0e ca 61 95 1f 55 26 7f "
+  "7c 28 78 c1 22 84 2d ad b2 8b 01 bd 5f 8c 02 5f "
+  "7e 22 84 18 a6 73 c0 3d 6b c0 c7 36 d0 a2 95 46 "
+  "bd 67 f7 86 d9 d6 92 cc ea 77 8d 71 d9 8c 20 63 "
+  "b7 a7 10 92 18 7a 4d 35 af 10 81 11 d8 3e 83 ea "
+  "e4 6c 46 aa 34 27 7e 06 04 45 89 90 37 88 f1 d5 "
+  "e7 ce e2 5f b4 85 e9 29 49 11 88 14 d6 f2 c3 ee "
+  "36 14 89 01 6f 32 7f b5 bc 51 7e b5 04 70 bf fa "
+  "1a fa 5f 4c e9 aa 0c e5 b8 ee 19 bf 55 01 b9 58 ";
+
+// RSASSA-PSS Signature Example 9.3
+// Message to be signed:
+static const char message_9_3[] =
+  "0a fa d4 2c cd 4f c6 06 54 a5 50 02 d2 28 f5 2a "
+  "4a 5f e0 3b 8b bb 08 ca 82 da ca 55 8b 44 db e1 "
+  "26 6e 50 c0 e7 45 a3 6d 9d 29 04 e3 40 8a bc d1 "
+  "fd 56 99 94 06 3f 4a 75 cc 72 f2 fe e2 a0 cd 89 "
+  "3a 43 af 1c 5b 8b 48 7d f0 a7 16 10 02 4e 4f 6d "
+  "df 9f 28 ad 08 13 c1 aa b9 1b cb 3c 90 64 d5 ff "
+  "74 2d ef fe a6 57 09 41 39 36 9e 5e a6 f4 a9 63 "
+  "19 a5 cc 82 24 14 5b 54 50 62 75 8f ef d1 fe 34 "
+  "09 ae 16 92 59 c6 cd fd 6b 5f 29 58 e3 14 fa ec "
+  "be 69 d2 ca ce 58 ee 55 17 9a b9 b3 e6 d1 ec c1 "
+  "4a 55 7c 5f eb e9 88 59 52 64 fc 5d a1 c5 71 46 "
+  "2e ca 79 8a 18 a1 a4 94 0c da b4 a3 e9 20 09 cc "
+  "d4 2e 1e 94 7b 13 14 e3 22 38 a2 de ce 7d 23 a8 "
+  "9b 5b 30 c7 51 fd 0a 4a 43 0d 2c 54 85 94 ";
+// Salt:
+static const char salt_9_3[] =
+  "9a 2b 00 7e 80 97 8b bb 19 2c 35 4e b7 da 9a ed "
+  "fc 74 db f5 ";
+// Signature:
+static const char signature_9_3[] =
+  "48 44 08 f3 89 8c d5 f5 34 83 f8 08 19 ef bf 27 "
+  "08 c3 4d 27 a8 b2 a6 fa e8 b3 22 f9 24 02 37 f9 "
+  "81 81 7a ca 18 46 f1 08 4d aa 6d 7c 07 95 f6 e5 "
+  "bf 1a f5 9c 38 e1 85 84 37 ce 1f 7e c4 19 b9 8c "
+  "87 36 ad f6 dd 9a 00 b1 80 6d 2b d3 ad 0a 73 77 "
+  "5e 05 f5 2d fe f3 a5 9a b4 b0 81 43 f0 df 05 cd "
+  "1a d9 d0 4b ec ec a6 da a4 a2 12 98 03 e2 00 cb "
+  "c7 77 87 ca f4 c1 d0 66 3a 6c 59 87 b6 05 95 20 "
+  "19 78 2c af 2e c1 42 6d 68 fb 94 ed 1d 4b e8 16 "
+  "a7 ed 08 1b 77 e6 ab 33 0b 3f fc 07 38 20 fe cd "
+  "e3 72 7f cb e2 95 ee 61 a0 50 a3 43 65 86 37 c3 "
+  "fd 65 9c fb 63 73 6d e3 2d 9f 90 d3 c2 f6 3e ca ";
+
+// RSASSA-PSS Signature Example 9.4
+// Message to be signed:
+static const char message_9_4[] =
+  "1d fd 43 b4 6c 93 db 82 62 9b da e2 bd 0a 12 b8 "
+  "82 ea 04 c3 b4 65 f5 cf 93 02 3f 01 05 96 26 db "
+  "be 99 f2 6b b1 be 94 9d dd d1 6d c7 f3 de bb 19 "
+  "a1 94 62 7f 0b 22 44 34 df 7d 87 00 e9 e9 8b 06 "
+  "e3 60 c1 2f db e3 d1 9f 51 c9 68 4e b9 08 9e cb "
+  "b0 a2 f0 45 03 99 d3 f5 9e ac 72 94 08 5d 04 4f "
+  "53 93 c6 ce 73 74 23 d8 b8 6c 41 53 70 d3 89 e3 "
+  "0b 9f 0a 3c 02 d2 5d 00 82 e8 ad 6f 3f 1e f2 4a "
+  "45 c3 cf 82 b3 83 36 70 63 a4 d4 61 3e 42 64 f0 "
+  "1b 2d ac 2e 5a a4 20 43 f8 fb 5f 69 fa 87 1d 14 "
+  "fb 27 3e 76 7a 53 1c 40 f0 2f 34 3b c2 fb 45 a0 "
+  "c7 e0 f6 be 25 61 92 3a 77 21 1d 66 a6 e2 db b4 "
+  "3c 36 63 50 be ae 22 da 3a c2 c1 f5 07 70 96 fc "
+  "b5 c4 bf 25 5f 75 74 35 1a e0 b1 e1 f0 36 32 81 "
+  "7c 08 56 d4 a8 ba 97 af bd c8 b8 58 55 40 2b c5 "
+  "69 26 fc ec 20 9f 9e a8 ";
+// Salt:
+static const char salt_9_4[] =
+  "70 f3 82 bd df 4d 5d 2d d8 8b 3b c7 b7 30 8b e6 "
+  "32 b8 40 45 ";
+// Signature:
+static const char signature_9_4[] =
+  "84 eb eb 48 1b e5 98 45 b4 64 68 ba fb 47 1c 01 "
+  "12 e0 2b 23 5d 84 b5 d9 11 cb d1 92 6e e5 07 4a "
+  "e0 42 44 95 cb 20 e8 23 08 b8 eb b6 5f 41 9a 03 "
+  "fb 40 e7 2b 78 98 1d 88 aa d1 43 05 36 85 17 2c "
+  "97 b2 9c 8b 7b f0 ae 73 b5 b2 26 3c 40 3d a0 ed "
+  "2f 80 ff 74 50 af 78 28 eb 8b 86 f0 02 8b d2 a8 "
+  "b1 76 a4 d2 28 cc ce a1 83 94 f2 38 b0 9f f7 58 "
+  "cc 00 bc 04 30 11 52 35 57 42 f2 82 b5 4e 66 3a "
+  "91 9e 70 9d 8d a2 4a de 55 00 a7 b9 aa 50 22 6e "
+  "0c a5 29 23 e6 c2 d8 60 ec 50 ff 48 0f a5 74 77 "
+  "e8 2b 05 65 f4 37 9f 79 c7 72 d5 c2 da 80 af 9f "
+  "bf 32 5e ce 6f c2 0b 00 96 16 14 be e8 9a 18 3e ";
+
+// RSASSA-PSS Signature Example 9.5
+// Message to be signed:
+static const char message_9_5[] =
+  "1b dc 6e 7c 98 fb 8c f5 4e 9b 09 7b 66 a8 31 e9 "
+  "cf e5 2d 9d 48 88 44 8e e4 b0 97 80 93 ba 1d 7d "
+  "73 ae 78 b3 a6 2b a4 ad 95 cd 28 9c cb 9e 00 52 "
+  "26 bb 3d 17 8b cc aa 82 1f b0 44 a4 e2 1e e9 76 "
+  "96 c1 4d 06 78 c9 4c 2d ae 93 b0 ad 73 92 22 18 "
+  "55 3d aa 7e 44 eb e5 77 25 a7 a4 5c c7 2b 9b 21 "
+  "38 a6 b1 7c 8d b4 11 ce 82 79 ee 12 41 af f0 a8 "
+  "be c6 f7 7f 87 ed b0 c6 9c b2 72 36 e3 43 5a 80 "
+  "0b 19 2e 4f 11 e5 19 e3 fe 30 fc 30 ea cc ca 4f "
+  "bb 41 76 90 29 bf 70 8e 81 7a 9e 68 38 05 be 67 "
+  "fa 10 09 84 68 3b 74 83 8e 3b cf fa 79 36 6e ed "
+  "1d 48 1c 76 72 91 18 83 8f 31 ba 8a 04 8a 93 c1 "
+  "be 44 24 59 8e 8d f6 32 8b 7a 77 88 0a 3f 9c 7e "
+  "2e 8d fc a8 eb 5a 26 fb 86 bd c5 56 d4 2b be 01 "
+  "d9 fa 6e d8 06 46 49 1c 93 41 ";
+// Salt:
+static const char salt_9_5[] =
+  "d6 89 25 7a 86 ef fa 68 21 2c 5e 0c 61 9e ca 29 "
+  "5f b9 1b 67 ";
+// Signature:
+static const char signature_9_5[] =
+  "82 10 2d f8 cb 91 e7 17 99 19 a0 4d 26 d3 35 d6 "
+  "4f bc 2f 87 2c 44 83 39 43 24 1d e8 45 48 10 27 "
+  "4c df 3d b5 f4 2d 42 3d b1 52 af 71 35 f7 01 42 "
+  "0e 39 b4 94 a6 7c bf d1 9f 91 19 da 23 3a 23 da "
+  "5c 64 39 b5 ba 0d 2b c3 73 ee e3 50 70 01 37 8d "
+  "4a 40 73 85 6b 7f e2 ab a0 b5 ee 93 b2 7f 4a fe "
+  "c7 d4 d1 20 92 1c 83 f6 06 76 5b 02 c1 9e 4d 6a "
+  "1a 3b 95 fa 4c 42 29 51 be 4f 52 13 10 77 ef 17 "
+  "17 97 29 cd df bd b5 69 50 db ac ee fe 78 cb 16 "
+  "64 0a 09 9e a5 6d 24 38 9e ef 10 f8 fe cb 31 ba "
+  "3e a3 b2 27 c0 a8 66 98 bb 89 e3 e9 36 39 05 bf "
+  "22 77 7b 2a 3a a5 21 b6 5b 4c ef 76 d8 3b de 4c ";
+
+// RSASSA-PSS Signature Example 9.6
+// Message to be signed:
+static const char message_9_6[] =
+  "88 c7 a9 f1 36 04 01 d9 0e 53 b1 01 b6 1c 53 25 "
+  "c3 c7 5d b1 b4 11 fb eb 8e 83 0b 75 e9 6b 56 67 "
+  "0a d2 45 40 4e 16 79 35 44 ee 35 4b c6 13 a9 0c "
+  "c9 84 87 15 a7 3d b5 89 3e 7f 6d 27 98 15 c0 c1 "
+  "de 83 ef 8e 29 56 e3 a5 6e d2 6a 88 8d 7a 9c dc "
+  "d0 42 f4 b1 6b 7f a5 1e f1 a0 57 36 62 d1 6a 30 "
+  "2d 0e c5 b2 85 d2 e0 3a d9 65 29 c8 7b 3d 37 4d "
+  "b3 72 d9 5b 24 43 d0 61 b6 b1 a3 50 ba 87 80 7e "
+  "d0 83 af d1 eb 05 c3 f5 2f 4e ba 5e d2 22 77 14 "
+  "fd b5 0b 9d 9d 9d d6 81 4f 62 f6 27 2f cd 5c db "
+  "ce 7a 9e f7 97 ";
+// Salt:
+static const char salt_9_6[] =
+  "c2 5f 13 bf 67 d0 81 67 1a 04 81 a1 f1 82 0d 61 "
+  "3b ba 22 76 ";
+// Signature:
+static const char signature_9_6[] =
+  "a7 fd b0 d2 59 16 5c a2 c8 8d 00 bb f1 02 8a 86 "
+  "7d 33 76 99 d0 61 19 3b 17 a9 64 8e 14 cc bb aa "
+  "de ac aa cd ec 81 5e 75 71 29 4e bb 8a 11 7a f2 "
+  "05 fa 07 8b 47 b0 71 2c 19 9e 3a d0 51 35 c5 04 "
+  "c2 4b 81 70 51 15 74 08 02 48 79 92 ff d5 11 d4 "
+  "af c6 b8 54 49 1e b3 f0 dd 52 31 39 54 2f f1 5c "
+  "31 01 ee 85 54 35 17 c6 a3 c7 94 17 c6 7e 2d d9 "
+  "aa 74 1e 9a 29 b0 6d cb 59 3c 23 36 b3 67 0a e3 "
+  "af ba c7 c3 e7 6e 21 54 73 e8 66 e3 38 ca 24 4d "
+  "e0 0b 62 62 4d 6b 94 26 82 2c ea e9 f8 cc 46 08 "
+  "95 f4 12 50 07 3f d4 5c 5a 1e 7b 42 5c 20 4a 42 "
+  "3a 69 91 59 f6 90 3e 71 0b 37 a7 bb 2b c8 04 9f ";
+
+// Example 10: A 2048-bit RSA Key Pair
+
+// RSA modulus n:
+static const char rsa_modulus_n_10[] =
+  "a5 dd 86 7a c4 cb 02 f9 0b 94 57 d4 8c 14 a7 70 "
+  "ef 99 1c 56 c3 9c 0e c6 5f d1 1a fa 89 37 ce a5 "
+  "7b 9b e7 ac 73 b4 5c 00 17 61 5b 82 d6 22 e3 18 "
+  "75 3b 60 27 c0 fd 15 7b e1 2f 80 90 fe e2 a7 ad "
+  "cd 0e ef 75 9f 88 ba 49 97 c7 a4 2d 58 c9 aa 12 "
+  "cb 99 ae 00 1f e5 21 c1 3b b5 43 14 45 a8 d5 ae "
+  "4f 5e 4c 7e 94 8a c2 27 d3 60 40 71 f2 0e 57 7e "
+  "90 5f be b1 5d fa f0 6d 1d e5 ae 62 53 d6 3a 6a "
+  "21 20 b3 1a 5d a5 da bc 95 50 60 0e 20 f2 7d 37 "
+  "39 e2 62 79 25 fe a3 cc 50 9f 21 df f0 4e 6e ea "
+  "45 49 c5 40 d6 80 9f f9 30 7e ed e9 1f ff 58 73 "
+  "3d 83 85 a2 37 d6 d3 70 5a 33 e3 91 90 09 92 07 "
+  "0d f7 ad f1 35 7c f7 e3 70 0c e3 66 7d e8 3f 17 "
+  "b8 df 17 78 db 38 1d ce 09 cb 4a d0 58 a5 11 00 "
+  "1a 73 81 98 ee 27 cf 55 a1 3b 75 45 39 90 65 82 "
+  "ec 8b 17 4b d5 8d 5d 1f 3d 76 7c 61 37 21 ae 05 ";
+// RSA public exponent e:
+static const char rsa_public_exponent_e_10[] =
+  "01 00 01 ";
+
+// RSASSA-PSS Signature Example 10.1
+// Message to be signed:
+static const char message_10_1[] =
+  "88 31 77 e5 12 6b 9b e2 d9 a9 68 03 27 d5 37 0c "
+  "6f 26 86 1f 58 20 c4 3d a6 7a 3a d6 09 ";
+// Salt:
+static const char salt_10_1[] =
+  "04 e2 15 ee 6f f9 34 b9 da 70 d7 73 0c 87 34 ab "
+  "fc ec de 89 ";
+// Signature:
+static const char signature_10_1[] =
+  "82 c2 b1 60 09 3b 8a a3 c0 f7 52 2b 19 f8 73 54 "
+  "06 6c 77 84 7a bf 2a 9f ce 54 2d 0e 84 e9 20 c5 "
+  "af b4 9f fd fd ac e1 65 60 ee 94 a1 36 96 01 14 "
+  "8e ba d7 a0 e1 51 cf 16 33 17 91 a5 72 7d 05 f2 "
+  "1e 74 e7 eb 81 14 40 20 69 35 d7 44 76 5a 15 e7 "
+  "9f 01 5c b6 6c 53 2c 87 a6 a0 59 61 c8 bf ad 74 "
+  "1a 9a 66 57 02 28 94 39 3e 72 23 73 97 96 c0 2a "
+  "77 45 5d 0f 55 5b 0e c0 1d df 25 9b 62 07 fd 0f "
+  "d5 76 14 ce f1 a5 57 3b aa ff 4e c0 00 69 95 16 "
+  "59 b8 5f 24 30 0a 25 16 0c a8 52 2d c6 e6 72 7e "
+  "57 d0 19 d7 e6 36 29 b8 fe 5e 89 e2 5c c1 5b eb "
+  "3a 64 75 77 55 92 99 28 0b 9b 28 f7 9b 04 09 00 "
+  "0b e2 5b bd 96 40 8b a3 b4 3c c4 86 18 4d d1 c8 "
+  "e6 25 53 fa 1a f4 04 0f 60 66 3d e7 f5 e4 9c 04 "
+  "38 8e 25 7f 1c e8 9c 95 da b4 8a 31 5d 9b 66 b1 "
+  "b7 62 82 33 87 6f f2 38 52 30 d0 70 d0 7e 16 66 ";
+
+// RSASSA-PSS Signature Example 10.2
+// Message to be signed:
+static const char message_10_2[] =
+  "dd 67 0a 01 46 58 68 ad c9 3f 26 13 19 57 a5 0c "
+  "52 fb 77 7c db aa 30 89 2c 9e 12 36 11 64 ec 13 "
+  "97 9d 43 04 81 18 e4 44 5d b8 7b ee 58 dd 98 7b "
+  "34 25 d0 20 71 d8 db ae 80 70 8b 03 9d bb 64 db "
+  "d1 de 56 57 d9 fe d0 c1 18 a5 41 43 74 2e 0f f3 "
+  "c8 7f 74 e4 58 57 64 7a f3 f7 9e b0 a1 4c 9d 75 "
+  "ea 9a 1a 04 b7 cf 47 8a 89 7a 70 8f d9 88 f4 8e "
+  "80 1e db 0b 70 39 df 8c 23 bb 3c 56 f4 e8 21 ac ";
+// Salt:
+static const char salt_10_2[] =
+  "8b 2b dd 4b 40 fa f5 45 c7 78 dd f9 bc 1a 49 cb "
+  "57 f9 b7 1b ";
+// Signature:
+static const char signature_10_2[] =
+  "14 ae 35 d9 dd 06 ba 92 f7 f3 b8 97 97 8a ed 7c "
+  "d4 bf 5f f0 b5 85 a4 0b d4 6c e1 b4 2c d2 70 30 "
+  "53 bb 90 44 d6 4e 81 3d 8f 96 db 2d d7 00 7d 10 "
+  "11 8f 6f 8f 84 96 09 7a d7 5e 1f f6 92 34 1b 28 "
+  "92 ad 55 a6 33 a1 c5 5e 7f 0a 0a d5 9a 0e 20 3a "
+  "5b 82 78 ae c5 4d d8 62 2e 28 31 d8 71 74 f8 ca "
+  "ff 43 ee 6c 46 44 53 45 d8 4a 59 65 9b fb 92 ec "
+  "d4 c8 18 66 86 95 f3 47 06 f6 68 28 a8 99 59 63 "
+  "7f 2b f3 e3 25 1c 24 bd ba 4d 4b 76 49 da 00 22 "
+  "21 8b 11 9c 84 e7 9a 65 27 ec 5b 8a 5f 86 1c 15 "
+  "99 52 e2 3e c0 5e 1e 71 73 46 fa ef e8 b1 68 68 "
+  "25 bd 2b 26 2f b2 53 10 66 c0 de 09 ac de 2e 42 "
+  "31 69 07 28 b5 d8 5e 11 5a 2f 6b 92 b7 9c 25 ab "
+  "c9 bd 93 99 ff 8b cf 82 5a 52 ea 1f 56 ea 76 dd "
+  "26 f4 3b aa fa 18 bf a9 2a 50 4c bd 35 69 9e 26 "
+  "d1 dc c5 a2 88 73 85 f3 c6 32 32 f0 6f 32 44 c3 ";
+
+// RSASSA-PSS Signature Example 10.3
+// Message to be signed:
+static const char message_10_3[] =
+  "48 b2 b6 a5 7a 63 c8 4c ea 85 9d 65 c6 68 28 4b "
+  "08 d9 6b dc aa be 25 2d b0 e4 a9 6c b1 ba c6 01 "
+  "93 41 db 6f be fb 8d 10 6b 0e 90 ed a6 bc c6 c6 "
+  "26 2f 37 e7 ea 9c 7e 5d 22 6b d7 df 85 ec 5e 71 "
+  "ef ff 2f 54 c5 db 57 7f f7 29 ff 91 b8 42 49 1d "
+  "e2 74 1d 0c 63 16 07 df 58 6b 90 5b 23 b9 1a f1 "
+  "3d a1 23 04 bf 83 ec a8 a7 3e 87 1f f9 db ";
+// Salt:
+static const char salt_10_3[] =
+  "4e 96 fc 1b 39 8f 92 b4 46 71 01 0c 0d c3 ef d6 "
+  "e2 0c 2d 73 ";
+// Signature:
+static const char signature_10_3[] =
+  "6e 3e 4d 7b 6b 15 d2 fb 46 01 3b 89 00 aa 5b bb "
+  "39 39 cf 2c 09 57 17 98 70 42 02 6e e6 2c 74 c5 "
+  "4c ff d5 d7 d5 7e fb bf 95 0a 0f 5c 57 4f a0 9d "
+  "3f c1 c9 f5 13 b0 5b 4f f5 0d d8 df 7e df a2 01 "
+  "02 85 4c 35 e5 92 18 01 19 a7 0c e5 b0 85 18 2a "
+  "a0 2d 9e a2 aa 90 d1 df 03 f2 da ae 88 5b a2 f5 "
+  "d0 5a fd ac 97 47 6f 06 b9 3b 5b c9 4a 1a 80 aa "
+  "91 16 c4 d6 15 f3 33 b0 98 89 2b 25 ff ac e2 66 "
+  "f5 db 5a 5a 3b cc 10 a8 24 ed 55 aa d3 5b 72 78 "
+  "34 fb 8c 07 da 28 fc f4 16 a5 d9 b2 22 4f 1f 8b "
+  "44 2b 36 f9 1e 45 6f de a2 d7 cf e3 36 72 68 de "
+  "03 07 a4 c7 4e 92 41 59 ed 33 39 3d 5e 06 55 53 "
+  "1c 77 32 7b 89 82 1b de df 88 01 61 c7 8c d4 19 "
+  "6b 54 19 f7 ac c3 f1 3e 5e bf 16 1b 6e 7c 67 24 "
+  "71 6c a3 3b 85 c2 e2 56 40 19 2a c2 85 96 51 d5 "
+  "0b de 7e b9 76 e5 1c ec 82 8b 98 b6 56 3b 86 bb ";
+
+// RSASSA-PSS Signature Example 10.4
+// Message to be signed:
+static const char message_10_4[] =
+  "0b 87 77 c7 f8 39 ba f0 a6 4b bb db c5 ce 79 75 "
+  "5c 57 a2 05 b8 45 c1 74 e2 d2 e9 05 46 a0 89 c4 "
+  "e6 ec 8a df fa 23 a7 ea 97 ba e6 b6 5d 78 2b 82 "
+  "db 5d 2b 5a 56 d2 2a 29 a0 5e 7c 44 33 e2 b8 2a "
+  "62 1a bb a9 0a dd 05 ce 39 3f c4 8a 84 05 42 45 "
+  "1a ";
+// Salt:
+static const char salt_10_4[] =
+  "c7 cd 69 8d 84 b6 51 28 d8 83 5e 3a 8b 1e b0 e0 "
+  "1c b5 41 ec ";
+// Signature:
+static const char signature_10_4[] =
+  "34 04 7f f9 6c 4d c0 dc 90 b2 d4 ff 59 a1 a3 61 "
+  "a4 75 4b 25 5d 2e e0 af 7d 8b f8 7c 9b c9 e7 dd "
+  "ee de 33 93 4c 63 ca 1c 0e 3d 26 2c b1 45 ef 93 "
+  "2a 1f 2c 0a 99 7a a6 a3 4f 8e ae e7 47 7d 82 cc "
+  "f0 90 95 a6 b8 ac ad 38 d4 ee c9 fb 7e ab 7a d0 "
+  "2d a1 d1 1d 8e 54 c1 82 5e 55 bf 58 c2 a2 32 34 "
+  "b9 02 be 12 4f 9e 90 38 a8 f6 8f a4 5d ab 72 f6 "
+  "6e 09 45 bf 1d 8b ac c9 04 4c 6f 07 09 8c 9f ce "
+  "c5 8a 3a ab 10 0c 80 51 78 15 5f 03 0a 12 4c 45 "
+  "0e 5a cb da 47 d0 e4 f1 0b 80 a2 3f 80 3e 77 4d "
+  "02 3b 00 15 c2 0b 9f 9b be 7c 91 29 63 38 d5 ec "
+  "b4 71 ca fb 03 20 07 b6 7a 60 be 5f 69 50 4a 9f "
+  "01 ab b3 cb 46 7b 26 0e 2b ce 86 0b e8 d9 5b f9 "
+  "2c 0c 8e 14 96 ed 1e 52 85 93 a4 ab b6 df 46 2d "
+  "de 8a 09 68 df fe 46 83 11 68 57 a2 32 f5 eb f6 "
+  "c8 5b e2 38 74 5a d0 f3 8f 76 7a 5f db f4 86 fb ";
+
+// RSASSA-PSS Signature Example 10.5
+// Message to be signed:
+static const char message_10_5[] =
+  "f1 03 6e 00 8e 71 e9 64 da dc 92 19 ed 30 e1 7f "
+  "06 b4 b6 8a 95 5c 16 b3 12 b1 ed df 02 8b 74 97 "
+  "6b ed 6b 3f 6a 63 d4 e7 78 59 24 3c 9c cc dc 98 "
+  "01 65 23 ab b0 24 83 b3 55 91 c3 3a ad 81 21 3b "
+  "b7 c7 bb 1a 47 0a ab c1 0d 44 25 6c 4d 45 59 d9 "
+  "16 ";
+// Salt:
+static const char salt_10_5[] =
+  "ef a8 bf f9 62 12 b2 f4 a3 f3 71 a1 0d 57 41 52 "
+  "65 5f 5d fb ";
+// Signature:
+static const char signature_10_5[] =
+  "7e 09 35 ea 18 f4 d6 c1 d1 7c e8 2e b2 b3 83 6c "
+  "55 b3 84 58 9c e1 9d fe 74 33 63 ac 99 48 d1 f3 "
+  "46 b7 bf dd fe 92 ef d7 8a db 21 fa ef c8 9a de "
+  "42 b1 0f 37 40 03 fe 12 2e 67 42 9a 1c b8 cb d1 "
+  "f8 d9 01 45 64 c4 4d 12 01 16 f4 99 0f 1a 6e 38 "
+  "77 4c 19 4b d1 b8 21 32 86 b0 77 b0 49 9d 2e 7b "
+  "3f 43 4a b1 22 89 c5 56 68 4d ee d7 81 31 93 4b "
+  "b3 dd 65 37 23 6f 7c 6f 3d cb 09 d4 76 be 07 72 "
+  "1e 37 e1 ce ed 9b 2f 7b 40 68 87 bd 53 15 73 05 "
+  "e1 c8 b4 f8 4d 73 3b c1 e1 86 fe 06 cc 59 b6 ed "
+  "b8 f4 bd 7f fe fd f4 f7 ba 9c fb 9d 57 06 89 b5 "
+  "a1 a4 10 9a 74 6a 69 08 93 db 37 99 25 5a 0c b9 "
+  "21 5d 2d 1c d4 90 59 0e 95 2e 8c 87 86 aa 00 11 "
+  "26 52 52 47 0c 04 1d fb c3 ee c7 c3 cb f7 1c 24 "
+  "86 9d 11 5c 0c b4 a9 56 f5 6d 53 0b 80 ab 58 9a "
+  "cf ef c6 90 75 1d df 36 e8 d3 83 f8 3c ed d2 cc ";
+
+// RSASSA-PSS Signature Example 10.6
+// Message to be signed:
+static const char message_10_6[] =
+  "25 f1 08 95 a8 77 16 c1 37 45 0b b9 51 9d fa a1 "
+  "f2 07 fa a9 42 ea 88 ab f7 1e 9c 17 98 00 85 b5 "
+  "55 ae ba b7 62 64 ae 2a 3a b9 3c 2d 12 98 11 91 "
+  "dd ac 6f b5 94 9e b3 6a ee 3c 5d a9 40 f0 07 52 "
+  "c9 16 d9 46 08 fa 7d 97 ba 6a 29 15 b6 88 f2 03 "
+  "23 d4 e9 d9 68 01 d8 9a 72 ab 58 92 dc 21 17 c0 "
+  "74 34 fc f9 72 e0 58 cf 8c 41 ca 4b 4f f5 54 f7 "
+  "d5 06 8a d3 15 5f ce d0 f3 12 5b c0 4f 91 93 37 "
+  "8a 8f 5c 4c 3b 8c b4 dd 6d 1c c6 9d 30 ec ca 6e "
+  "aa 51 e3 6a 05 73 0e 9e 34 2e 85 5b af 09 9d ef "
+  "b8 af d7 ";
+// Salt:
+static const char salt_10_6[] =
+  "ad 8b 15 23 70 36 46 22 4b 66 0b 55 08 85 91 7c "
+  "a2 d1 df 28 ";
+// Signature:
+static const char signature_10_6[] =
+  "6d 3b 5b 87 f6 7e a6 57 af 21 f7 54 41 97 7d 21 "
+  "80 f9 1b 2c 5f 69 2d e8 29 55 69 6a 68 67 30 d9 "
+  "b9 77 8d 97 07 58 cc b2 60 71 c2 20 9f fb d6 12 "
+  "5b e2 e9 6e a8 1b 67 cb 9b 93 08 23 9f da 17 f7 "
+  "b2 b6 4e cd a0 96 b6 b9 35 64 0a 5a 1c b4 2a 91 "
+  "55 b1 c9 ef 7a 63 3a 02 c5 9f 0d 6e e5 9b 85 2c "
+  "43 b3 50 29 e7 3c 94 0f f0 41 0e 8f 11 4e ed 46 "
+  "bb d0 fa e1 65 e4 2b e2 52 8a 40 1c 3b 28 fd 81 "
+  "8e f3 23 2d ca 9f 4d 2a 0f 51 66 ec 59 c4 23 96 "
+  "d6 c1 1d bc 12 15 a5 6f a1 71 69 db 95 75 34 3e "
+  "f3 4f 9d e3 2a 49 cd c3 17 49 22 f2 29 c2 3e 18 "
+  "e4 5d f9 35 31 19 ec 43 19 ce dc e7 a1 7c 64 08 "
+  "8c 1f 6f 52 be 29 63 41 00 b3 91 9d 38 f3 d1 ed "
+  "94 e6 89 1e 66 a7 3b 8f b8 49 f5 87 4d f5 94 59 "
+  "e2 98 c7 bb ce 2e ee 78 2a 19 5a a6 6f e2 d0 73 "
+  "2b 25 e5 95 f5 7d 3e 06 1b 1f c3 e4 06 3b f9 8f ";
+
+struct SignatureExample {
+  const char* message;
+  const char* salt;
+  const char* signature;
+};
+
+struct PSSTestVector {
+  const char* modulus_n;
+  const char* public_exponent_e;
+  SignatureExample example[6];
+};
+
+static const PSSTestVector pss_test[] = {
+  {
+    rsa_modulus_n_1,
+    rsa_public_exponent_e_1,
+    {
+      { message_1_1, salt_1_1, signature_1_1 },
+      { message_1_2, salt_1_2, signature_1_2 },
+      { message_1_3, salt_1_3, signature_1_3 },
+      { message_1_4, salt_1_4, signature_1_4 },
+      { message_1_5, salt_1_5, signature_1_5 },
+      { message_1_6, salt_1_6, signature_1_6 },
+    }
+  },
+  {
+    rsa_modulus_n_9,
+    rsa_public_exponent_e_9,
+    {
+      { message_9_1, salt_9_1, signature_9_1 },
+      { message_9_2, salt_9_2, signature_9_2 },
+      { message_9_3, salt_9_3, signature_9_3 },
+      { message_9_4, salt_9_4, signature_9_4 },
+      { message_9_5, salt_9_5, signature_9_5 },
+      { message_9_6, salt_9_6, signature_9_6 },
+    }
+  },
+  {
+    rsa_modulus_n_10,
+    rsa_public_exponent_e_10,
+    {
+      { message_10_1, salt_10_1, signature_10_1 },
+      { message_10_2, salt_10_2, signature_10_2 },
+      { message_10_3, salt_10_3, signature_10_3 },
+      { message_10_4, salt_10_4, signature_10_4 },
+      { message_10_5, salt_10_5, signature_10_5 },
+      { message_10_6, salt_10_6, signature_10_6 },
+    }
+  },
+};
+
+static uint8_t HexDigitValue(char digit) {
+  if ('0' <= digit && digit <= '9')
+    return digit - '0';
+  if ('a' <= digit && digit <= 'f')
+    return digit - 'a' + 10;
+  return digit - 'A' + 10;
+}
+
+static bool DecodeTestInput(const char* in, std::vector<uint8_t>* out) {
+  out->clear();
+  while (in[0] != '\0') {
+    if (!isxdigit(in[0]) || !isxdigit(in[1]) || in[2] != ' ')
+      return false;
+    uint8_t octet = HexDigitValue(in[0]) * 16 + HexDigitValue(in[1]);
+    out->push_back(octet);
+    in += 3;
+  }
+  return true;
+}
+
+// PrependASN1Length prepends an ASN.1 serialized length to the beginning of
+// |out|.
+static void PrependASN1Length(std::vector<uint8_t>* out, size_t len) {
+  if (len < 128) {
+    out->insert(out->begin(), static_cast<uint8_t>(len));
+  } else if (len < 256) {
+    out->insert(out->begin(), static_cast<uint8_t>(len));
+    out->insert(out->begin(), 0x81);
+  } else if (len < 0x10000) {
+    out->insert(out->begin(), static_cast<uint8_t>(len));
+    out->insert(out->begin(), static_cast<uint8_t>(len >> 8));
+    out->insert(out->begin(), 0x82);
+  } else {
+    CHECK(false) << "ASN.1 length not handled: " << len;
+  }
+}
+
+static bool EncodeRSAPublicKey(const std::vector<uint8_t>& modulus_n,
+                               const std::vector<uint8_t>& public_exponent_e,
+                               std::vector<uint8_t>* public_key_info) {
+  // The public key is specified as the following ASN.1 structure:
+  //   SubjectPublicKeyInfo  ::=  SEQUENCE  {
+  //       algorithm            AlgorithmIdentifier,
+  //       subjectPublicKey     BIT STRING  }
+  //
+  // The algorithm is specified as the following ASN.1 structure:
+  //    AlgorithmIdentifier  ::=  SEQUENCE  {
+  //        algorithm               OBJECT IDENTIFIER,
+  //        parameters              ANY DEFINED BY algorithm OPTIONAL  }
+  //
+  // An RSA public key is specified as the following ASN.1 structure:
+  //    RSAPublicKey ::= SEQUENCE {
+  //        modulus           INTEGER,  -- n
+  //        publicExponent    INTEGER   -- e
+  //    }
+  static const uint8_t kIntegerTag = 0x02;
+  static const uint8_t kBitStringTag = 0x03;
+  static const uint8_t kSequenceTag = 0x30;
+  public_key_info->clear();
+
+  // Encode the public exponent e as an INTEGER.
+  public_key_info->insert(public_key_info->begin(),
+                          public_exponent_e.begin(),
+                          public_exponent_e.end());
+  PrependASN1Length(public_key_info, public_exponent_e.size());
+  public_key_info->insert(public_key_info->begin(), kIntegerTag);
+
+  // Encode the modulus n as an INTEGER.
+  public_key_info->insert(public_key_info->begin(),
+                          modulus_n.begin(), modulus_n.end());
+  size_t modulus_size = modulus_n.size();
+  if (modulus_n[0] & 0x80) {
+    public_key_info->insert(public_key_info->begin(), 0x00);
+    modulus_size++;
+  }
+  PrependASN1Length(public_key_info, modulus_size);
+  public_key_info->insert(public_key_info->begin(), kIntegerTag);
+
+  // Encode the RSAPublicKey SEQUENCE.
+  PrependASN1Length(public_key_info, public_key_info->size());
+  public_key_info->insert(public_key_info->begin(), kSequenceTag);
+
+  // Encode the BIT STRING.
+  // Number of unused bits.
+  public_key_info->insert(public_key_info->begin(), 0x00);
+  PrependASN1Length(public_key_info, public_key_info->size());
+  public_key_info->insert(public_key_info->begin(), kBitStringTag);
+
+  // Encode the AlgorithmIdentifier.
+  static const uint8_t algorithm[] = {
+      0x30, 0x0d,  // a SEQUENCE of length 13
+      0x06, 0x09,  // an OBJECT IDENTIFIER of length 9
+      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+  };
+  public_key_info->insert(public_key_info->begin(),
+                          algorithm, algorithm + sizeof(algorithm));
+
+  // Encode the outermost SEQUENCE.
+  PrependASN1Length(public_key_info, public_key_info->size());
+  public_key_info->insert(public_key_info->begin(), kSequenceTag);
+
+  return true;
+}
+
+TEST(SignatureVerifierTest, VerifyRSAPSS) {
+  for (unsigned int i = 0; i < arraysize(pss_test); i++) {
+    SCOPED_TRACE(i);
+    std::vector<uint8_t> modulus_n;
+    std::vector<uint8_t> public_exponent_e;
+    ASSERT_TRUE(DecodeTestInput(pss_test[i].modulus_n, &modulus_n));
+    ASSERT_TRUE(DecodeTestInput(pss_test[i].public_exponent_e,
+                                &public_exponent_e));
+    std::vector<uint8_t> public_key_info;
+    ASSERT_TRUE(EncodeRSAPublicKey(modulus_n, public_exponent_e,
+                                   &public_key_info));
+
+    for (unsigned int j = 0; j < arraysize(pss_test[i].example); j++) {
+      SCOPED_TRACE(j);
+      std::vector<uint8_t> message;
+      std::vector<uint8_t> salt;
+      std::vector<uint8_t> signature;
+      ASSERT_TRUE(DecodeTestInput(pss_test[i].example[j].message, &message));
+      ASSERT_TRUE(DecodeTestInput(pss_test[i].example[j].salt, &salt));
+      ASSERT_TRUE(DecodeTestInput(pss_test[i].example[j].signature,
+                                  &signature));
+
+      crypto::SignatureVerifier verifier;
+      bool ok;
+
+      // Positive test.
+      ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+                                     crypto::SignatureVerifier::SHA1,
+                                     salt.size(),
+                                     &signature[0], signature.size(),
+                                     &public_key_info[0],
+                                     public_key_info.size());
+      ASSERT_TRUE(ok);
+      verifier.VerifyUpdate(&message[0], message.size());
+      ok = verifier.VerifyFinal();
+      EXPECT_TRUE(ok);
+
+      // Modify the first byte of the message.
+      ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+                                     crypto::SignatureVerifier::SHA1,
+                                     salt.size(),
+                                     &signature[0], signature.size(),
+                                     &public_key_info[0],
+                                     public_key_info.size());
+      ASSERT_TRUE(ok);
+      message[0] += 1;
+      verifier.VerifyUpdate(&message[0], message.size());
+      message[0] -= 1;
+      ok = verifier.VerifyFinal();
+      EXPECT_FALSE(ok);
+
+      // Truncate the message.
+      ASSERT_FALSE(message.empty());
+      ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+                                     crypto::SignatureVerifier::SHA1,
+                                     salt.size(),
+                                     &signature[0], signature.size(),
+                                     &public_key_info[0],
+                                     public_key_info.size());
+      ASSERT_TRUE(ok);
+      verifier.VerifyUpdate(&message[0], message.size() - 1);
+      ok = verifier.VerifyFinal();
+      EXPECT_FALSE(ok);
+
+      // Corrupt the signature.
+      signature[0] += 1;
+      ok = verifier.VerifyInitRSAPSS(crypto::SignatureVerifier::SHA1,
+                                     crypto::SignatureVerifier::SHA1,
+                                     salt.size(),
+                                     &signature[0], signature.size(),
+                                     &public_key_info[0],
+                                     public_key_info.size());
+      signature[0] -= 1;
+      ASSERT_TRUE(ok);
+      verifier.VerifyUpdate(&message[0], message.size());
+      ok = verifier.VerifyFinal();
+      EXPECT_FALSE(ok);
+    }
+  }
+}
diff --git a/libchrome/crypto/symmetric_key.cc b/libchrome/crypto/symmetric_key.cc
new file mode 100644
index 0000000..e3ecf62
--- /dev/null
+++ b/libchrome/crypto/symmetric_key.cc
@@ -0,0 +1,110 @@
+// 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 "crypto/symmetric_key.h"
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "crypto/openssl_util.h"
+
+namespace crypto {
+
+SymmetricKey::~SymmetricKey() {
+  std::fill(key_.begin(), key_.end(), '\0');  // Zero out the confidential key.
+}
+
+// static
+std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey(
+    Algorithm algorithm,
+    size_t key_size_in_bits) {
+  DCHECK_EQ(AES, algorithm);
+
+  // Whitelist supported key sizes to avoid accidentaly relying on
+  // algorithms available in NSS but not BoringSSL and vice
+  // versa. Note that BoringSSL does not support AES-192.
+  if (key_size_in_bits != 128 && key_size_in_bits != 256)
+    return nullptr;
+
+  size_t key_size_in_bytes = key_size_in_bits / 8;
+  DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
+
+  if (key_size_in_bytes == 0)
+    return nullptr;
+
+  OpenSSLErrStackTracer err_tracer(FROM_HERE);
+  std::unique_ptr<SymmetricKey> key(new SymmetricKey);
+  uint8_t* key_data = reinterpret_cast<uint8_t*>(
+      base::WriteInto(&key->key_, key_size_in_bytes + 1));
+
+  int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes));
+  return rv == 1 ? std::move(key) : nullptr;
+}
+
+// static
+std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPassword(
+    Algorithm algorithm,
+    const std::string& password,
+    const std::string& salt,
+    size_t iterations,
+    size_t key_size_in_bits) {
+  DCHECK(algorithm == AES || algorithm == HMAC_SHA1);
+
+  if (algorithm == AES) {
+    // Whitelist supported key sizes to avoid accidentaly relying on
+    // algorithms available in NSS but not BoringSSL and vice
+    // versa. Note that BoringSSL does not support AES-192.
+    if (key_size_in_bits != 128 && key_size_in_bits != 256)
+      return nullptr;
+  }
+
+  size_t key_size_in_bytes = key_size_in_bits / 8;
+  DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8);
+
+  if (key_size_in_bytes == 0)
+    return nullptr;
+
+  OpenSSLErrStackTracer err_tracer(FROM_HERE);
+  std::unique_ptr<SymmetricKey> key(new SymmetricKey);
+  uint8_t* key_data = reinterpret_cast<uint8_t*>(
+      base::WriteInto(&key->key_, key_size_in_bytes + 1));
+  int rv = PKCS5_PBKDF2_HMAC_SHA1(
+      password.data(), password.length(),
+      reinterpret_cast<const uint8_t*>(salt.data()), salt.length(),
+      static_cast<unsigned>(iterations),
+      key_size_in_bytes, key_data);
+  return rv == 1 ? std::move(key) : nullptr;
+}
+
+// static
+std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm,
+                                                   const std::string& raw_key) {
+  if (algorithm == AES) {
+    // Whitelist supported key sizes to avoid accidentaly relying on
+    // algorithms available in NSS but not BoringSSL and vice
+    // versa. Note that BoringSSL does not support AES-192.
+    if (raw_key.size() != 128/8 && raw_key.size() != 256/8)
+      return nullptr;
+  }
+
+  std::unique_ptr<SymmetricKey> key(new SymmetricKey);
+  key->key_ = raw_key;
+  return key;
+}
+
+bool SymmetricKey::GetRawKey(std::string* raw_key) {
+  *raw_key = key_;
+  return true;
+}
+
+SymmetricKey::SymmetricKey() = default;
+
+}  // namespace crypto
diff --git a/libchrome/crypto/symmetric_key.h b/libchrome/crypto/symmetric_key.h
new file mode 100644
index 0000000..8862708
--- /dev/null
+++ b/libchrome/crypto/symmetric_key.h
@@ -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.
+
+#ifndef CRYPTO_SYMMETRIC_KEY_H_
+#define CRYPTO_SYMMETRIC_KEY_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "crypto/crypto_export.h"
+
+#if defined(NACL_WIN64)
+// See comments for crypto_nacl_win64 in crypto.gyp.
+// Must test for NACL_WIN64 before OS_WIN since former is a subset of latter.
+#include "crypto/scoped_capi_types.h"
+#elif defined(USE_NSS_CERTS) || \
+    (!defined(USE_OPENSSL) && (defined(OS_WIN) || defined(OS_MACOSX)))
+#include "crypto/scoped_nss_types.h"
+#endif
+
+namespace crypto {
+
+// Wraps a platform-specific symmetric key and allows it to be held in a
+// scoped_ptr.
+class CRYPTO_EXPORT SymmetricKey {
+ public:
+  // Defines the algorithm that a key will be used with. See also
+  // classs Encrptor.
+  enum Algorithm {
+    AES,
+    HMAC_SHA1,
+  };
+
+  virtual ~SymmetricKey();
+
+  // Generates a random key suitable to be used with |algorithm| and of
+  // |key_size_in_bits| bits. |key_size_in_bits| must be a multiple of 8.
+  // The caller is responsible for deleting the returned SymmetricKey.
+  static std::unique_ptr<SymmetricKey> GenerateRandomKey(
+      Algorithm algorithm,
+      size_t key_size_in_bits);
+
+  // Derives a key from the supplied password and salt using PBKDF2, suitable
+  // for use with specified |algorithm|. Note |algorithm| is not the algorithm
+  // used to derive the key from the password. |key_size_in_bits| must be a
+  // multiple of 8. The caller is responsible for deleting the returned
+  // SymmetricKey.
+  static std::unique_ptr<SymmetricKey> DeriveKeyFromPassword(
+      Algorithm algorithm,
+      const std::string& password,
+      const std::string& salt,
+      size_t iterations,
+      size_t key_size_in_bits);
+
+  // Imports an array of key bytes in |raw_key|. This key may have been
+  // generated by GenerateRandomKey or DeriveKeyFromPassword and exported with
+  // GetRawKey, or via another compatible method. The key must be of suitable
+  // size for use with |algorithm|. The caller owns the returned SymmetricKey.
+  static std::unique_ptr<SymmetricKey> Import(Algorithm algorithm,
+                                              const std::string& raw_key);
+#if defined(NACL_WIN64)
+  HCRYPTKEY key() const { return key_.get(); }
+#elif defined(USE_OPENSSL)
+  const std::string& key() { return key_; }
+#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
+  PK11SymKey* key() const { return key_.get(); }
+#endif
+
+  // Extracts the raw key from the platform specific data.
+  // Warning: |raw_key| holds the raw key as bytes and thus must be handled
+  // carefully.
+  bool GetRawKey(std::string* raw_key);
+
+ private:
+#if defined(NACL_WIN64)
+  SymmetricKey(HCRYPTPROV provider, HCRYPTKEY key,
+               const void* key_data, size_t key_size_in_bytes);
+
+  ScopedHCRYPTPROV provider_;
+  ScopedHCRYPTKEY key_;
+
+  // Contains the raw key, if it is known during initialization and when it
+  // is likely that the associated |provider_| will be unable to export the
+  // |key_|. This is the case of HMAC keys when the key size exceeds 16 bytes
+  // when using the default RSA provider.
+  // TODO(rsleevi): See if KP_EFFECTIVE_KEYLEN is the reason why CryptExportKey
+  // fails with NTE_BAD_KEY/NTE_BAD_LEN
+  std::string raw_key_;
+#elif defined(USE_OPENSSL)
+  SymmetricKey() {}
+  std::string key_;
+#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
+  explicit SymmetricKey(PK11SymKey* key);
+  ScopedPK11SymKey key_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(SymmetricKey);
+};
+
+}  // namespace crypto
+
+#endif  // CRYPTO_SYMMETRIC_KEY_H_
diff --git a/libchrome/crypto/symmetric_key_nss.cc b/libchrome/crypto/symmetric_key_nss.cc
new file mode 100644
index 0000000..e3aacc7
--- /dev/null
+++ b/libchrome/crypto/symmetric_key_nss.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 "crypto/symmetric_key.h"
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace crypto {
+
+SymmetricKey::~SymmetricKey() {}
+
+// static
+SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
+                                              size_t key_size_in_bits) {
+  DCHECK_EQ(AES, algorithm);
+
+  EnsureNSSInit();
+
+  // Whitelist supported key sizes to avoid accidentaly relying on
+  // algorithms available in NSS but not BoringSSL and vice
+  // versa. Note that BoringSSL does not support AES-192.
+  if (key_size_in_bits != 128 && key_size_in_bits != 256)
+    return NULL;
+
+  ScopedPK11Slot slot(PK11_GetInternalSlot());
+  if (!slot.get())
+    return NULL;
+
+  PK11SymKey* sym_key = PK11_KeyGen(slot.get(), CKM_AES_KEY_GEN, NULL,
+                                    key_size_in_bits / 8, NULL);
+  if (!sym_key)
+    return NULL;
+
+  return new SymmetricKey(sym_key);
+}
+
+// static
+SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
+                                                  const std::string& password,
+                                                  const std::string& salt,
+                                                  size_t iterations,
+                                                  size_t key_size_in_bits) {
+  EnsureNSSInit();
+  if (salt.empty() || iterations == 0 || key_size_in_bits == 0)
+    return NULL;
+
+  if (algorithm == AES) {
+    // Whitelist supported key sizes to avoid accidentaly relying on
+    // algorithms available in NSS but not BoringSSL and vice
+    // versa. Note that BoringSSL does not support AES-192.
+    if (key_size_in_bits != 128 && key_size_in_bits != 256)
+      return NULL;
+  }
+
+  SECItem password_item;
+  password_item.type = siBuffer;
+  password_item.data = reinterpret_cast<unsigned char*>(
+      const_cast<char *>(password.data()));
+  password_item.len = password.size();
+
+  SECItem salt_item;
+  salt_item.type = siBuffer;
+  salt_item.data = reinterpret_cast<unsigned char*>(
+      const_cast<char *>(salt.data()));
+  salt_item.len = salt.size();
+
+  SECOidTag cipher_algorithm =
+      algorithm == AES ? SEC_OID_AES_256_CBC : SEC_OID_HMAC_SHA1;
+  ScopedSECAlgorithmID alg_id(PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2,
+                                                          cipher_algorithm,
+                                                          SEC_OID_HMAC_SHA1,
+                                                          key_size_in_bits / 8,
+                                                          iterations,
+                                                          &salt_item));
+  if (!alg_id.get())
+    return NULL;
+
+  ScopedPK11Slot slot(PK11_GetInternalSlot());
+  if (!slot.get())
+    return NULL;
+
+  PK11SymKey* sym_key = PK11_PBEKeyGen(slot.get(), alg_id.get(), &password_item,
+                                       PR_FALSE, NULL);
+  if (!sym_key)
+    return NULL;
+
+  return new SymmetricKey(sym_key);
+}
+
+// static
+SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
+                                   const std::string& raw_key) {
+  EnsureNSSInit();
+
+  if (algorithm == AES) {
+    // Whitelist supported key sizes to avoid accidentaly relying on
+    // algorithms available in NSS but not BoringSSL and vice
+    // versa. Note that BoringSSL does not support AES-192.
+    if (raw_key.size() != 128/8 && raw_key.size() != 256/8)
+      return NULL;
+  }
+
+  CK_MECHANISM_TYPE cipher =
+      algorithm == AES ? CKM_AES_CBC : CKM_SHA_1_HMAC;
+
+  SECItem key_item;
+  key_item.type = siBuffer;
+  key_item.data = reinterpret_cast<unsigned char*>(
+      const_cast<char *>(raw_key.data()));
+  key_item.len = raw_key.size();
+
+  ScopedPK11Slot slot(PK11_GetInternalSlot());
+  if (!slot.get())
+    return NULL;
+
+  // The exact value of the |origin| argument doesn't matter to NSS as long as
+  // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a
+  // placeholder.
+  PK11SymKey* sym_key = PK11_ImportSymKey(slot.get(), cipher, PK11_OriginUnwrap,
+                                          CKA_ENCRYPT, &key_item, NULL);
+  if (!sym_key)
+    return NULL;
+
+  return new SymmetricKey(sym_key);
+}
+
+bool SymmetricKey::GetRawKey(std::string* raw_key) {
+  SECStatus rv = PK11_ExtractKeyValue(key_.get());
+  if (SECSuccess != rv)
+    return false;
+
+  SECItem* key_item = PK11_GetKeyData(key_.get());
+  if (!key_item)
+    return false;
+
+  raw_key->assign(reinterpret_cast<char*>(key_item->data), key_item->len);
+  return true;
+}
+
+SymmetricKey::SymmetricKey(PK11SymKey* key) : key_(key) {
+  DCHECK(key);
+}
+
+}  // namespace crypto
diff --git a/libchrome/crypto/symmetric_key_unittest.cc b/libchrome/crypto/symmetric_key_unittest.cc
new file mode 100644
index 0000000..d954761
--- /dev/null
+++ b/libchrome/crypto/symmetric_key_unittest.cc
@@ -0,0 +1,215 @@
+// 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 "crypto/symmetric_key.h"
+
+#include <memory>
+#include <string>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SymmetricKeyTest, GenerateRandomKey) {
+  std::unique_ptr<crypto::SymmetricKey> key(
+      crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
+  ASSERT_TRUE(key);
+  std::string raw_key;
+  EXPECT_TRUE(key->GetRawKey(&raw_key));
+  EXPECT_EQ(32U, raw_key.size());
+
+  // Do it again and check that the keys are different.
+  // (Note: this has a one-in-10^77 chance of failure!)
+  std::unique_ptr<crypto::SymmetricKey> key2(
+      crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
+  ASSERT_TRUE(key2);
+  std::string raw_key2;
+  EXPECT_TRUE(key2->GetRawKey(&raw_key2));
+  EXPECT_EQ(32U, raw_key2.size());
+  EXPECT_NE(raw_key, raw_key2);
+}
+
+TEST(SymmetricKeyTest, ImportGeneratedKey) {
+  std::unique_ptr<crypto::SymmetricKey> key1(
+      crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256));
+  ASSERT_TRUE(key1);
+  std::string raw_key1;
+  EXPECT_TRUE(key1->GetRawKey(&raw_key1));
+
+  std::unique_ptr<crypto::SymmetricKey> key2(
+      crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key1));
+  ASSERT_TRUE(key2);
+
+  std::string raw_key2;
+  EXPECT_TRUE(key2->GetRawKey(&raw_key2));
+
+  EXPECT_EQ(raw_key1, raw_key2);
+}
+
+TEST(SymmetricKeyTest, ImportDerivedKey) {
+  std::unique_ptr<crypto::SymmetricKey> key1(
+      crypto::SymmetricKey::DeriveKeyFromPassword(
+          crypto::SymmetricKey::HMAC_SHA1, "password", "somesalt", 1024, 160));
+  ASSERT_TRUE(key1);
+  std::string raw_key1;
+  EXPECT_TRUE(key1->GetRawKey(&raw_key1));
+
+  std::unique_ptr<crypto::SymmetricKey> key2(
+      crypto::SymmetricKey::Import(crypto::SymmetricKey::HMAC_SHA1, raw_key1));
+  ASSERT_TRUE(key2);
+
+  std::string raw_key2;
+  EXPECT_TRUE(key2->GetRawKey(&raw_key2));
+
+  EXPECT_EQ(raw_key1, raw_key2);
+}
+
+struct PBKDF2TestVector {
+  crypto::SymmetricKey::Algorithm algorithm;
+  const char* password;
+  const char* salt;
+  unsigned int rounds;
+  unsigned int key_size_in_bits;
+  const char* expected;  // ASCII encoded hex bytes
+};
+
+class SymmetricKeyDeriveKeyFromPasswordTest
+    : public testing::TestWithParam<PBKDF2TestVector> {
+};
+
+TEST_P(SymmetricKeyDeriveKeyFromPasswordTest, DeriveKeyFromPassword) {
+  PBKDF2TestVector test_data(GetParam());
+  std::unique_ptr<crypto::SymmetricKey> key(
+      crypto::SymmetricKey::DeriveKeyFromPassword(
+          test_data.algorithm, test_data.password, test_data.salt,
+          test_data.rounds, test_data.key_size_in_bits));
+  ASSERT_TRUE(key);
+
+  std::string raw_key;
+  key->GetRawKey(&raw_key);
+  EXPECT_EQ(test_data.key_size_in_bits / 8, raw_key.size());
+  EXPECT_EQ(test_data.expected,
+            base::ToLowerASCII(base::HexEncode(raw_key.data(),
+                                               raw_key.size())));
+}
+
+static const PBKDF2TestVector kTestVectors[] = {
+  // These tests come from
+  // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "salt",
+    1,
+    160,
+    "0c60c80f961f0e71f3a9b524af6012062fe037a6",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "salt",
+    2,
+    160,
+    "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "salt",
+    4096,
+    160,
+    "4b007901b765489abead49d926f721d065a429c1",
+  },
+  // This test takes over 30s to run on the trybots.
+#if 0
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "salt",
+    16777216,
+    160,
+    "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984",
+  },
+#endif
+
+  // These tests come from RFC 3962, via BSD source code at
+  // http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/bioctl/pbkdf2.c?rev=HEAD&content-type=text/plain
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "ATHENA.MIT.EDUraeburn",
+    1,
+    160,
+    "cdedb5281bb2f801565a1122b25635150ad1f7a0",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "ATHENA.MIT.EDUraeburn",
+    2,
+    160,
+    "01dbee7f4a9e243e988b62c73cda935da05378b9",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "ATHENA.MIT.EDUraeburn",
+    1200,
+    160,
+    "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddb",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "password",
+    "\022" "4VxxV4\022", /* 0x1234567878563412 */
+    5,
+    160,
+    "d1daa78615f287e6a1c8b120d7062a493f98d203",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+    "pass phrase equals block size",
+    1200,
+    160,
+    "139c30c0966bc32ba55fdbf212530ac9c5ec59f1",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+    "pass phrase exceeds block size",
+    1200,
+    160,
+    "9ccad6d468770cd51b10e6a68721be611a8b4d28",
+  },
+  {
+    crypto::SymmetricKey::HMAC_SHA1,
+    "\360\235\204\236", /* g-clef (0xf09d849e) */
+    "EXAMPLE.COMpianist",
+    50,
+    160,
+    "6b9cf26d45455a43a5b8bb276a403b39e7fe37a0",
+  },
+
+  // Regression tests for AES keys, derived from the Linux NSS implementation.
+  {
+    crypto::SymmetricKey::AES,
+    "A test password",
+    "saltsalt",
+    1,
+    256,
+    "44899a7777f0e6e8b752f875f02044b8ac593de146de896f2e8a816e315a36de",
+  },
+  {
+    crypto::SymmetricKey::AES,
+    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
+    "pass phrase exceeds block size",
+    20,
+    256,
+    "e0739745dc28b8721ba402e05214d2ac1eab54cf72bee1fba388297a09eb493c",
+  },
+};
+
+INSTANTIATE_TEST_CASE_P(, SymmetricKeyDeriveKeyFromPasswordTest,
+                        testing::ValuesIn(kTestVectors));
diff --git a/libchrome/crypto/third_party/nss/chromium-blapi.h b/libchrome/crypto/third_party/nss/chromium-blapi.h
new file mode 100644
index 0000000..2ca772e
--- /dev/null
+++ b/libchrome/crypto/third_party/nss/chromium-blapi.h
@@ -0,0 +1,101 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * ***** 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 security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: blapi.h,v 1.27 2007/11/09 18:49:32 wtc%google.com Exp $ */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_
+
+#include "crypto/third_party/nss/chromium-blapit.h"
+
+/******************************************/
+
+extern SHA256Context *SHA256_NewContext(void);
+extern void SHA256_DestroyContext(SHA256Context *cx, PRBool freeit);
+extern void SHA256_Begin(SHA256Context *cx);
+extern void SHA256_Update(SHA256Context *cx, const unsigned char *input,
+			unsigned int inputLen);
+extern void SHA256_End(SHA256Context *cx, unsigned char *digest,
+		     unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
+			      unsigned int src_length);
+extern SECStatus SHA256_Hash(unsigned char *dest, const char *src);
+extern void SHA256_TraceState(SHA256Context *cx);
+extern unsigned int SHA256_FlattenSize(SHA256Context *cx);
+extern SECStatus SHA256_Flatten(SHA256Context *cx,unsigned char *space);
+extern SHA256Context * SHA256_Resurrect(unsigned char *space, void *arg);
+extern void SHA256_Clone(SHA256Context *dest, SHA256Context *src);
+
+/******************************************/
+
+extern SHA512Context *SHA512_NewContext(void);
+extern void SHA512_DestroyContext(SHA512Context *cx, PRBool freeit);
+extern void SHA512_Begin(SHA512Context *cx);
+extern void SHA512_Update(SHA512Context *cx, const unsigned char *input,
+			unsigned int inputLen);
+extern void SHA512_End(SHA512Context *cx, unsigned char *digest,
+		     unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
+			      unsigned int src_length);
+extern SECStatus SHA512_Hash(unsigned char *dest, const char *src);
+extern void SHA512_TraceState(SHA512Context *cx);
+extern unsigned int SHA512_FlattenSize(SHA512Context *cx);
+extern SECStatus SHA512_Flatten(SHA512Context *cx,unsigned char *space);
+extern SHA512Context * SHA512_Resurrect(unsigned char *space, void *arg);
+extern void SHA512_Clone(SHA512Context *dest, SHA512Context *src);
+
+/******************************************/
+
+extern SHA384Context *SHA384_NewContext(void);
+extern void SHA384_DestroyContext(SHA384Context *cx, PRBool freeit);
+extern void SHA384_Begin(SHA384Context *cx);
+extern void SHA384_Update(SHA384Context *cx, const unsigned char *input,
+			unsigned int inputLen);
+extern void SHA384_End(SHA384Context *cx, unsigned char *digest,
+		     unsigned int *digestLen, unsigned int maxDigestLen);
+extern SECStatus SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
+			      unsigned int src_length);
+extern SECStatus SHA384_Hash(unsigned char *dest, const char *src);
+extern void SHA384_TraceState(SHA384Context *cx);
+extern unsigned int SHA384_FlattenSize(SHA384Context *cx);
+extern SECStatus SHA384_Flatten(SHA384Context *cx,unsigned char *space);
+extern SHA384Context * SHA384_Resurrect(unsigned char *space, void *arg);
+extern void SHA384_Clone(SHA384Context *dest, SHA384Context *src);
+
+#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPI_H_ */
diff --git a/libchrome/crypto/third_party/nss/chromium-blapit.h b/libchrome/crypto/third_party/nss/chromium-blapit.h
new file mode 100644
index 0000000..938547a
--- /dev/null
+++ b/libchrome/crypto/third_party/nss/chromium-blapit.h
@@ -0,0 +1,91 @@
+/*
+ * blapit.h - public data structures for the crypto library
+ *
+ * ***** 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 security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dr Vipul Gupta <vipul.gupta@sun.com> and
+ *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * 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 ***** */
+/* $Id: blapit.h,v 1.20 2007/02/28 19:47:37 rrelyea%redhat.com Exp $ */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_
+
+#include "crypto/third_party/nss/chromium-prtypes.h"
+
+/*
+** A status code. Status's are used by procedures that return status
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong. Correct testing of status codes:
+**
+**      SECStatus rv;
+**      rv = some_function (some_argument);
+**      if (rv != SECSuccess)
+**              do_an_error_thing();
+**
+*/
+typedef enum _SECStatus {
+    SECWouldBlock = -2,
+    SECFailure = -1,
+    SECSuccess = 0
+} SECStatus;
+
+#define SHA256_LENGTH 		32 	/* bytes */
+#define SHA384_LENGTH 		48 	/* bytes */
+#define SHA512_LENGTH 		64 	/* bytes */
+#define HASH_LENGTH_MAX         SHA512_LENGTH
+
+/*
+ * Input block size for each hash algorithm.
+ */
+
+#define SHA256_BLOCK_LENGTH      64     /* bytes */
+#define SHA384_BLOCK_LENGTH     128     /* bytes */
+#define SHA512_BLOCK_LENGTH     128     /* bytes */
+#define HASH_BLOCK_LENGTH_MAX   SHA512_BLOCK_LENGTH
+
+/***************************************************************************
+** Opaque objects
+*/
+
+struct SHA256ContextStr     ;
+struct SHA512ContextStr     ;
+
+typedef struct SHA256ContextStr     SHA256Context;
+typedef struct SHA512ContextStr     SHA512Context;
+/* SHA384Context is really a SHA512ContextStr.  This is not a mistake. */
+typedef struct SHA512ContextStr     SHA384Context;
+
+#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_BLAPIT_H_ */
diff --git a/libchrome/crypto/third_party/nss/chromium-nss.h b/libchrome/crypto/third_party/nss/chromium-nss.h
new file mode 100644
index 0000000..437e6bd
--- /dev/null
+++ b/libchrome/crypto/third_party/nss/chromium-nss.h
@@ -0,0 +1,79 @@
+ /* ***** 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 security libraries.
+  *
+  * The Initial Developer of the Original Code is
+  * Netscape Communications Corporation.
+  * Portions created by the Initial Developer are Copyright (C) 1994-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 ***** */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_
+
+// This file contains some functions we borrowed from NSS.
+
+#include <prtypes.h>
+#include <hasht.h>
+#include <keyhi.h>
+#include <secmod.h>
+
+#include "crypto/crypto_export.h"
+
+extern "C" SECStatus emsa_pss_verify(const unsigned char *mHash,
+                                     const unsigned char *em,
+                                     unsigned int emLen,
+                                     HASH_HashType hashAlg,
+                                     HASH_HashType maskHashAlg,
+                                     unsigned int sLen);
+
+// Like PK11_ImportEncryptedPrivateKeyInfo, but hardcoded for EC, and returns
+// the SECKEYPrivateKey.
+// See https://bugzilla.mozilla.org/show_bug.cgi?id=211546
+// When we use NSS 3.13.2 or later,
+// PK11_ImportEncryptedPrivateKeyInfoAndReturnKey can be used instead.
+SECStatus ImportEncryptedECPrivateKeyInfoAndReturnKey(
+    PK11SlotInfo* slot,
+    SECKEYEncryptedPrivateKeyInfo* epki,
+    SECItem* password,
+    SECItem* nickname,
+    SECItem* public_value,
+    PRBool permanent,
+    PRBool sensitive,
+    SECKEYPrivateKey** private_key,
+    void* wincx);
+
+// Like SEC_DerSignData.
+CRYPTO_EXPORT SECStatus DerSignData(PLArenaPool *arena,
+                                    SECItem *result,
+                                    SECItem *input,
+                                    SECKEYPrivateKey *key,
+                                    SECOidTag algo_id);
+
+#endif  // CRYPTO_THIRD_PARTY_NSS_CHROMIUM_NSS_H_
diff --git a/libchrome/crypto/third_party/nss/chromium-prtypes.h b/libchrome/crypto/third_party/nss/chromium-prtypes.h
new file mode 100644
index 0000000..d5ea8a9
--- /dev/null
+++ b/libchrome/crypto/third_party/nss/chromium-prtypes.h
@@ -0,0 +1,77 @@
+/* ***** 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 security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * 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 ***** */
+
+/* Emulates the real prtypes.h. Defines the types and macros that sha512.cc
+ * needs. */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_PRTYPES_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_PRTYPES_H_
+
+#include <limits.h>
+#include <stdint.h>
+
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+#define IS_LITTLE_ENDIAN 1
+#else
+#define IS_BIG_ENDIAN 1
+#endif
+
+/*
+ * The C language requires that 'long' be at least 32 bits. 2147483647 is the
+ * largest signed 32-bit integer.
+ */
+#if LONG_MAX > 2147483647L
+#define PR_BYTES_PER_LONG 8
+#else
+#define PR_BYTES_PER_LONG 4
+#endif
+
+#define HAVE_LONG_LONG
+
+#if defined(__linux__)
+#define LINUX
+#endif
+
+typedef uint8_t PRUint8;
+typedef uint32_t PRUint32;
+
+typedef int PRBool;
+
+#define PR_MIN(x,y) ((x)<(y)?(x):(y))
+
+#endif  /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_PRTYPES_H_ */
diff --git a/libchrome/crypto/third_party/nss/chromium-sha256.h b/libchrome/crypto/third_party/nss/chromium-sha256.h
new file mode 100644
index 0000000..52815ca
--- /dev/null
+++ b/libchrome/crypto/third_party/nss/chromium-sha256.h
@@ -0,0 +1,51 @@
+/* ***** 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 security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * 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 ***** */
+
+#ifndef CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_
+#define CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_
+
+#include "crypto/third_party/nss/chromium-prtypes.h"
+
+struct SHA256ContextStr {
+    union {
+	PRUint32 w[64];	    /* message schedule, input buffer, plus 48 words */
+	PRUint8  b[256];
+    } u;
+    PRUint32 h[8];		/* 8 state variables */
+    PRUint32 sizeHi,sizeLo;	/* 64-bit count of hashed bytes. */
+};
+
+#endif /* CRYPTO_THIRD_PARTY_NSS_CHROMIUM_SHA_256_H_ */
diff --git a/libchrome/crypto/third_party/nss/rsawrapr.c b/libchrome/crypto/third_party/nss/rsawrapr.c
new file mode 100644
index 0000000..73e498f
--- /dev/null
+++ b/libchrome/crypto/third_party/nss/rsawrapr.c
@@ -0,0 +1,160 @@
+/*
+ * PKCS#1 encoding and decoding functions.
+ * This file is believed to contain no code licensed from other parties.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "seccomon.h"
+#include "secerr.h"
+#include "sechash.h"
+
+/* Needed for RSA-PSS functions */
+static const unsigned char eightZeros[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+/*
+ * Mask generation function MGF1 as defined in PKCS #1 v2.1 / RFC 3447.
+ */
+static SECStatus
+MGF1(HASH_HashType hashAlg, unsigned char *mask, unsigned int maskLen,
+     const unsigned char *mgfSeed, unsigned int mgfSeedLen)
+{
+    unsigned int digestLen;
+    PRUint32 counter, rounds;
+    unsigned char *tempHash, *temp;
+    const SECHashObject *hash;
+    void *hashContext;
+    unsigned char C[4];
+
+    hash = HASH_GetHashObject(hashAlg);
+    if (hash == NULL)
+        return SECFailure;
+
+    hashContext = (*hash->create)();
+    rounds = (maskLen + hash->length - 1) / hash->length;
+    for (counter = 0; counter < rounds; counter++) {
+        C[0] = (unsigned char)((counter >> 24) & 0xff);
+        C[1] = (unsigned char)((counter >> 16) & 0xff);
+        C[2] = (unsigned char)((counter >> 8) & 0xff);
+        C[3] = (unsigned char)(counter & 0xff);
+
+        /* This could be optimized when the clone functions in
+         * rawhash.c are implemented. */
+        (*hash->begin)(hashContext);
+        (*hash->update)(hashContext, mgfSeed, mgfSeedLen); 
+        (*hash->update)(hashContext, C, sizeof C);
+
+        tempHash = mask + counter * hash->length;
+        if (counter != (rounds-1)) {
+            (*hash->end)(hashContext, tempHash, &digestLen, hash->length);
+        } else { /* we're in the last round and need to cut the hash */
+            temp = (unsigned char *)PORT_Alloc(hash->length);
+            (*hash->end)(hashContext, temp, &digestLen, hash->length);
+            PORT_Memcpy(tempHash, temp, maskLen - counter * hash->length);
+            PORT_Free(temp);
+        }
+    }
+    (*hash->destroy)(hashContext, PR_TRUE);
+
+    return SECSuccess;
+}
+
+/*
+ * Verify a RSA-PSS signature.
+ * Described in RFC 3447, section 9.1.2.
+ * We use mHash instead of M as input.
+ * emBits from the RFC is just modBits - 1, see section 8.1.2.
+ * We only support MGF1 as the MGF.
+ *
+ * NOTE: this code assumes modBits is a multiple of 8.
+ */
+SECStatus
+emsa_pss_verify(const unsigned char *mHash,
+                const unsigned char *em, unsigned int emLen,
+                HASH_HashType hashAlg, HASH_HashType maskHashAlg,
+                unsigned int sLen)
+{
+    const SECHashObject *hash;
+    void *hash_context;
+    unsigned char *db;
+    unsigned char *H_;  /* H' from the RFC */
+    unsigned int i, dbMaskLen;
+    SECStatus rv;
+
+    hash = HASH_GetHashObject(hashAlg);
+    dbMaskLen = emLen - hash->length - 1;
+
+    /* Step 3 + 4 + 6 */
+    if ((emLen < (hash->length + sLen + 2)) ||
+	(em[emLen - 1] != 0xbc) ||
+	((em[0] & 0x80) != 0)) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	return SECFailure;
+    }
+
+    /* Step 7 */
+    db = (unsigned char *)PORT_Alloc(dbMaskLen);
+    if (db == NULL) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    /* &em[dbMaskLen] points to H, used as mgfSeed */
+    MGF1(maskHashAlg, db, dbMaskLen, &em[dbMaskLen], hash->length);
+
+    /* Step 8 */
+    for (i = 0; i < dbMaskLen; i++) {
+	db[i] ^= em[i];
+    }
+
+    /* Step 9 */
+    db[0] &= 0x7f;
+
+    /* Step 10 */
+    for (i = 0; i < (dbMaskLen - sLen - 1); i++) {
+	if (db[i] != 0) {
+	    PORT_Free(db);
+	    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	    return SECFailure;
+	}
+    }
+    if (db[dbMaskLen - sLen - 1] != 0x01) {
+	PORT_Free(db);
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	return SECFailure;
+    }
+
+    /* Step 12 + 13 */
+    H_ = (unsigned char *)PORT_Alloc(hash->length);
+    if (H_ == NULL) {
+	PORT_Free(db);
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    hash_context = (*hash->create)();
+    if (hash_context == NULL) {
+	PORT_Free(db);
+	PORT_Free(H_);
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	return SECFailure;
+    }
+    (*hash->begin)(hash_context);
+    (*hash->update)(hash_context, eightZeros, 8);
+    (*hash->update)(hash_context, mHash, hash->length);
+    (*hash->update)(hash_context, &db[dbMaskLen - sLen], sLen);
+    (*hash->end)(hash_context, H_, &i, hash->length);
+    (*hash->destroy)(hash_context, PR_TRUE);
+
+    PORT_Free(db);
+
+    /* Step 14 */
+    if (PORT_Memcmp(H_, &em[dbMaskLen], hash->length) != 0) {
+	PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+	rv = SECFailure;
+    } else {
+	rv = SECSuccess;
+    }
+
+    PORT_Free(H_);
+    return rv;
+}
diff --git a/libchrome/crypto/third_party/nss/sha512.cc b/libchrome/crypto/third_party/nss/sha512.cc
new file mode 100644
index 0000000..78950cb
--- /dev/null
+++ b/libchrome/crypto/third_party/nss/sha512.cc
@@ -0,0 +1,1390 @@
+/*
+ * sha512.c - implementation of SHA256, SHA384 and SHA512
+ *
+ * ***** 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 security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * 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 ***** */
+/* $Id: sha512.c,v 1.9 2006/10/13 16:54:04 wtchang%redhat.com Exp $ */
+
+// Prevent manual unrolling in the sha256 code, which reduces the binary code
+// size from ~10k to ~1k.  The performance should be reasonable for our use.
+#define NOUNROLL256 1
+
+#include "crypto/third_party/nss/chromium-prtypes.h"  /* for PRUintXX */
+#if defined(_X86_) || defined(SHA_NO_LONG_LONG)
+#define NOUNROLL512 1
+#undef HAVE_LONG_LONG
+#endif
+#include "crypto/third_party/nss/chromium-blapi.h"
+#include "crypto/third_party/nss/chromium-sha256.h"    /* for struct SHA256ContextStr */
+
+#include <stdlib.h>
+#include <string.h>
+#define PORT_New(type) static_cast<type*>(malloc(sizeof(type)))
+#define PORT_ZFree(ptr, len) do { memset(ptr, 0, len); free(ptr); } while (0)
+#define PORT_Strlen(s) static_cast<unsigned int>(strlen(s))
+#define PORT_Memcpy memcpy
+
+/* ============= Common constants and defines ======================= */
+
+#define W ctx->u.w
+#define B ctx->u.b
+#define H ctx->h
+
+#define SHR(x,n) (x >> n)
+#define SHL(x,n) (x << n)
+#define Ch(x,y,z)  ((x & y) ^ (~x & z))
+#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
+
+/* Padding used with all flavors of SHA */
+static const PRUint8 pad[240] = {
+0x80,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
+   /* compiler will fill the rest in with zeros */
+};
+
+/* ============= SHA256 implemenmtation ================================== */
+
+/* SHA-256 constants, K256. */
+static const PRUint32 K256[64] = {
+    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/* SHA-256 initial hash values */
+static const PRUint32 H256[8] = {
+    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+};
+
+#if defined(_MSC_VER) && defined(_X86_)
+#ifndef FORCEINLINE
+#if (_MSC_VER >= 1200)
+#define FORCEINLINE __forceinline
+#else
+#define FORCEINLINE __inline
+#endif
+#endif
+#define FASTCALL __fastcall
+
+static FORCEINLINE PRUint32 FASTCALL
+swap4b(PRUint32 dwd)
+{
+    __asm {
+    	mov   eax,dwd
+	bswap eax
+    }
+}
+
+#define SHA_HTONL(x) swap4b(x)
+#define BYTESWAP4(x)  x = SHA_HTONL(x)
+
+#elif defined(LINUX) && defined(_X86_)
+#undef  __OPTIMIZE__
+#define __OPTIMIZE__ 1
+#undef  __pentium__
+#define __pentium__ 1
+#include <byteswap.h>
+#define SHA_HTONL(x) bswap_32(x)
+#define BYTESWAP4(x)  x = SHA_HTONL(x)
+
+#else /* neither windows nor Linux PC */
+#define SWAP4MASK  0x00FF00FF
+#define SHA_HTONL(x) (t1 = (x), t1 = (t1 << 16) | (t1 >> 16), \
+                      ((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK))
+#define BYTESWAP4(x)  x = SHA_HTONL(x)
+#endif
+
+#if defined(_MSC_VER) && defined(_X86_)
+#pragma intrinsic (_lrotr, _lrotl)
+#define ROTR32(x,n) _lrotr(x,n)
+#define ROTL32(x,n) _lrotl(x,n)
+#else
+#define ROTR32(x,n) ((x >> n) | (x << ((8 * sizeof x) - n)))
+#define ROTL32(x,n) ((x << n) | (x >> ((8 * sizeof x) - n)))
+#endif
+
+/* Capitol Sigma and lower case sigma functions */
+#define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22))
+#define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25))
+#define s0(x) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3))
+#define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10))
+
+SHA256Context *
+SHA256_NewContext(void)
+{
+    SHA256Context *ctx = PORT_New(SHA256Context);
+    return ctx;
+}
+
+void
+SHA256_DestroyContext(SHA256Context *ctx, PRBool freeit)
+{
+    if (freeit) {
+        PORT_ZFree(ctx, sizeof *ctx);
+    }
+}
+
+void
+SHA256_Begin(SHA256Context *ctx)
+{
+    memset(ctx, 0, sizeof *ctx);
+    memcpy(H, H256, sizeof H256);
+}
+
+static void
+SHA256_Compress(SHA256Context *ctx)
+{
+  {
+    register PRUint32 t1, t2;
+
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP4(W[0]);
+    BYTESWAP4(W[1]);
+    BYTESWAP4(W[2]);
+    BYTESWAP4(W[3]);
+    BYTESWAP4(W[4]);
+    BYTESWAP4(W[5]);
+    BYTESWAP4(W[6]);
+    BYTESWAP4(W[7]);
+    BYTESWAP4(W[8]);
+    BYTESWAP4(W[9]);
+    BYTESWAP4(W[10]);
+    BYTESWAP4(W[11]);
+    BYTESWAP4(W[12]);
+    BYTESWAP4(W[13]);
+    BYTESWAP4(W[14]);
+    BYTESWAP4(W[15]);
+#endif
+
+#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
+
+    /* prepare the "message schedule"   */
+#ifdef NOUNROLL256
+    {
+	int t;
+	for (t = 16; t < 64; ++t) {
+	    INITW(t);
+	}
+    }
+#else
+    INITW(16);
+    INITW(17);
+    INITW(18);
+    INITW(19);
+
+    INITW(20);
+    INITW(21);
+    INITW(22);
+    INITW(23);
+    INITW(24);
+    INITW(25);
+    INITW(26);
+    INITW(27);
+    INITW(28);
+    INITW(29);
+
+    INITW(30);
+    INITW(31);
+    INITW(32);
+    INITW(33);
+    INITW(34);
+    INITW(35);
+    INITW(36);
+    INITW(37);
+    INITW(38);
+    INITW(39);
+
+    INITW(40);
+    INITW(41);
+    INITW(42);
+    INITW(43);
+    INITW(44);
+    INITW(45);
+    INITW(46);
+    INITW(47);
+    INITW(48);
+    INITW(49);
+
+    INITW(50);
+    INITW(51);
+    INITW(52);
+    INITW(53);
+    INITW(54);
+    INITW(55);
+    INITW(56);
+    INITW(57);
+    INITW(58);
+    INITW(59);
+
+    INITW(60);
+    INITW(61);
+    INITW(62);
+    INITW(63);
+
+#endif
+#undef INITW
+  }
+  {
+    PRUint32 a, b, c, d, e, f, g, h;
+
+    a = H[0];
+    b = H[1];
+    c = H[2];
+    d = H[3];
+    e = H[4];
+    f = H[5];
+    g = H[6];
+    h = H[7];
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+    h += S1(e) + Ch(e,f,g) + K256[n] + W[n]; \
+    d += h; \
+    h += S0(a) + Maj(a,b,c);
+
+#ifdef NOUNROLL256
+    {
+	int t;
+	for (t = 0; t < 64; t+= 8) {
+	    ROUND(t+0,a,b,c,d,e,f,g,h)
+	    ROUND(t+1,h,a,b,c,d,e,f,g)
+	    ROUND(t+2,g,h,a,b,c,d,e,f)
+	    ROUND(t+3,f,g,h,a,b,c,d,e)
+	    ROUND(t+4,e,f,g,h,a,b,c,d)
+	    ROUND(t+5,d,e,f,g,h,a,b,c)
+	    ROUND(t+6,c,d,e,f,g,h,a,b)
+	    ROUND(t+7,b,c,d,e,f,g,h,a)
+	}
+    }
+#else
+    ROUND( 0,a,b,c,d,e,f,g,h)
+    ROUND( 1,h,a,b,c,d,e,f,g)
+    ROUND( 2,g,h,a,b,c,d,e,f)
+    ROUND( 3,f,g,h,a,b,c,d,e)
+    ROUND( 4,e,f,g,h,a,b,c,d)
+    ROUND( 5,d,e,f,g,h,a,b,c)
+    ROUND( 6,c,d,e,f,g,h,a,b)
+    ROUND( 7,b,c,d,e,f,g,h,a)
+
+    ROUND( 8,a,b,c,d,e,f,g,h)
+    ROUND( 9,h,a,b,c,d,e,f,g)
+    ROUND(10,g,h,a,b,c,d,e,f)
+    ROUND(11,f,g,h,a,b,c,d,e)
+    ROUND(12,e,f,g,h,a,b,c,d)
+    ROUND(13,d,e,f,g,h,a,b,c)
+    ROUND(14,c,d,e,f,g,h,a,b)
+    ROUND(15,b,c,d,e,f,g,h,a)
+
+    ROUND(16,a,b,c,d,e,f,g,h)
+    ROUND(17,h,a,b,c,d,e,f,g)
+    ROUND(18,g,h,a,b,c,d,e,f)
+    ROUND(19,f,g,h,a,b,c,d,e)
+    ROUND(20,e,f,g,h,a,b,c,d)
+    ROUND(21,d,e,f,g,h,a,b,c)
+    ROUND(22,c,d,e,f,g,h,a,b)
+    ROUND(23,b,c,d,e,f,g,h,a)
+
+    ROUND(24,a,b,c,d,e,f,g,h)
+    ROUND(25,h,a,b,c,d,e,f,g)
+    ROUND(26,g,h,a,b,c,d,e,f)
+    ROUND(27,f,g,h,a,b,c,d,e)
+    ROUND(28,e,f,g,h,a,b,c,d)
+    ROUND(29,d,e,f,g,h,a,b,c)
+    ROUND(30,c,d,e,f,g,h,a,b)
+    ROUND(31,b,c,d,e,f,g,h,a)
+
+    ROUND(32,a,b,c,d,e,f,g,h)
+    ROUND(33,h,a,b,c,d,e,f,g)
+    ROUND(34,g,h,a,b,c,d,e,f)
+    ROUND(35,f,g,h,a,b,c,d,e)
+    ROUND(36,e,f,g,h,a,b,c,d)
+    ROUND(37,d,e,f,g,h,a,b,c)
+    ROUND(38,c,d,e,f,g,h,a,b)
+    ROUND(39,b,c,d,e,f,g,h,a)
+
+    ROUND(40,a,b,c,d,e,f,g,h)
+    ROUND(41,h,a,b,c,d,e,f,g)
+    ROUND(42,g,h,a,b,c,d,e,f)
+    ROUND(43,f,g,h,a,b,c,d,e)
+    ROUND(44,e,f,g,h,a,b,c,d)
+    ROUND(45,d,e,f,g,h,a,b,c)
+    ROUND(46,c,d,e,f,g,h,a,b)
+    ROUND(47,b,c,d,e,f,g,h,a)
+
+    ROUND(48,a,b,c,d,e,f,g,h)
+    ROUND(49,h,a,b,c,d,e,f,g)
+    ROUND(50,g,h,a,b,c,d,e,f)
+    ROUND(51,f,g,h,a,b,c,d,e)
+    ROUND(52,e,f,g,h,a,b,c,d)
+    ROUND(53,d,e,f,g,h,a,b,c)
+    ROUND(54,c,d,e,f,g,h,a,b)
+    ROUND(55,b,c,d,e,f,g,h,a)
+
+    ROUND(56,a,b,c,d,e,f,g,h)
+    ROUND(57,h,a,b,c,d,e,f,g)
+    ROUND(58,g,h,a,b,c,d,e,f)
+    ROUND(59,f,g,h,a,b,c,d,e)
+    ROUND(60,e,f,g,h,a,b,c,d)
+    ROUND(61,d,e,f,g,h,a,b,c)
+    ROUND(62,c,d,e,f,g,h,a,b)
+    ROUND(63,b,c,d,e,f,g,h,a)
+#endif
+
+    H[0] += a;
+    H[1] += b;
+    H[2] += c;
+    H[3] += d;
+    H[4] += e;
+    H[5] += f;
+    H[6] += g;
+    H[7] += h;
+  }
+#undef ROUND
+}
+
+#undef s0
+#undef s1
+#undef S0
+#undef S1
+
+void
+SHA256_Update(SHA256Context *ctx, const unsigned char *input,
+		    unsigned int inputLen)
+{
+    unsigned int inBuf = ctx->sizeLo & 0x3f;
+    if (!inputLen)
+    	return;
+
+    /* Add inputLen into the count of bytes processed, before processing */
+    if ((ctx->sizeLo += inputLen) < inputLen)
+    	ctx->sizeHi++;
+
+    /* if data already in buffer, attemp to fill rest of buffer */
+    if (inBuf) {
+    	unsigned int todo = SHA256_BLOCK_LENGTH - inBuf;
+	if (inputLen < todo)
+	    todo = inputLen;
+	memcpy(B + inBuf, input, todo);
+	input    += todo;
+	inputLen -= todo;
+	if (inBuf + todo == SHA256_BLOCK_LENGTH)
+	    SHA256_Compress(ctx);
+    }
+
+    /* if enough data to fill one or more whole buffers, process them. */
+    while (inputLen >= SHA256_BLOCK_LENGTH) {
+    	memcpy(B, input, SHA256_BLOCK_LENGTH);
+	input    += SHA256_BLOCK_LENGTH;
+	inputLen -= SHA256_BLOCK_LENGTH;
+	SHA256_Compress(ctx);
+    }
+    /* if data left over, fill it into buffer */
+    if (inputLen)
+    	memcpy(B, input, inputLen);
+}
+
+void
+SHA256_End(SHA256Context *ctx, unsigned char *digest,
+           unsigned int *digestLen, unsigned int maxDigestLen)
+{
+    unsigned int inBuf = ctx->sizeLo & 0x3f;
+    unsigned int padLen = (inBuf < 56) ? (56 - inBuf) : (56 + 64 - inBuf);
+    PRUint32 hi, lo;
+#ifdef SWAP4MASK
+    PRUint32 t1;
+#endif
+
+    hi = (ctx->sizeHi << 3) | (ctx->sizeLo >> 29);
+    lo = (ctx->sizeLo << 3);
+
+    SHA256_Update(ctx, pad, padLen);
+
+#if defined(IS_LITTLE_ENDIAN)
+    W[14] = SHA_HTONL(hi);
+    W[15] = SHA_HTONL(lo);
+#else
+    W[14] = hi;
+    W[15] = lo;
+#endif
+    SHA256_Compress(ctx);
+
+    /* now output the answer */
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP4(H[0]);
+    BYTESWAP4(H[1]);
+    BYTESWAP4(H[2]);
+    BYTESWAP4(H[3]);
+    BYTESWAP4(H[4]);
+    BYTESWAP4(H[5]);
+    BYTESWAP4(H[6]);
+    BYTESWAP4(H[7]);
+#endif
+    padLen = PR_MIN(SHA256_LENGTH, maxDigestLen);
+    memcpy(digest, H, padLen);
+    if (digestLen)
+	*digestLen = padLen;
+}
+
+void SHA256_Clone(SHA256Context* dest, SHA256Context* src)
+{
+  memcpy(dest, src, sizeof *dest);
+}
+
+/* Comment out unused code, mostly the SHA384 and SHA512 implementations. */
+#if 0
+SECStatus
+SHA256_HashBuf(unsigned char *dest, const unsigned char *src,
+               unsigned int src_length)
+{
+    SHA256Context ctx;
+    unsigned int outLen;
+
+    SHA256_Begin(&ctx);
+    SHA256_Update(&ctx, src, src_length);
+    SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH);
+
+    return SECSuccess;
+}
+
+
+SECStatus
+SHA256_Hash(unsigned char *dest, const char *src)
+{
+    return SHA256_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+
+void SHA256_TraceState(SHA256Context *ctx) { }
+
+unsigned int
+SHA256_FlattenSize(SHA256Context *ctx)
+{
+    return sizeof *ctx;
+}
+
+SECStatus
+SHA256_Flatten(SHA256Context *ctx,unsigned char *space)
+{
+    PORT_Memcpy(space, ctx, sizeof *ctx);
+    return SECSuccess;
+}
+
+SHA256Context *
+SHA256_Resurrect(unsigned char *space, void *arg)
+{
+    SHA256Context *ctx = SHA256_NewContext();
+    if (ctx)
+	PORT_Memcpy(ctx, space, sizeof *ctx);
+    return ctx;
+}
+
+/* ======= SHA512 and SHA384 common constants and defines ================= */
+
+/* common #defines for SHA512 and SHA384 */
+#if defined(HAVE_LONG_LONG)
+#define ROTR64(x,n) ((x >> n) | (x << (64 - n)))
+#define ROTL64(x,n) ((x << n) | (x >> (64 - n)))
+
+#define S0(x) (ROTR64(x,28) ^ ROTR64(x,34) ^ ROTR64(x,39))
+#define S1(x) (ROTR64(x,14) ^ ROTR64(x,18) ^ ROTR64(x,41))
+#define s0(x) (t1 = x, ROTR64(t1, 1) ^ ROTR64(t1, 8) ^ SHR(t1,7))
+#define s1(x) (t2 = x, ROTR64(t2,19) ^ ROTR64(t2,61) ^ SHR(t2,6))
+
+#if PR_BYTES_PER_LONG == 8
+#define ULLC(hi,lo) 0x ## hi ## lo ## UL
+#elif defined(_MSC_VER)
+#define ULLC(hi,lo) 0x ## hi ## lo ## ui64
+#else
+#define ULLC(hi,lo) 0x ## hi ## lo ## ULL
+#endif
+
+#define SHA_MASK16 ULLC(0000FFFF,0000FFFF)
+#define SHA_MASK8  ULLC(00FF00FF,00FF00FF)
+#define SHA_HTONLL(x) (t1 = x, \
+  t1 = ((t1 & SHA_MASK8 ) <<  8) | ((t1 >>  8) & SHA_MASK8 ), \
+  t1 = ((t1 & SHA_MASK16) << 16) | ((t1 >> 16) & SHA_MASK16), \
+  (t1 >> 32) | (t1 << 32))
+#define BYTESWAP8(x)  x = SHA_HTONLL(x)
+
+#else /* no long long */
+
+#if defined(IS_LITTLE_ENDIAN)
+#define ULLC(hi,lo) { 0x ## lo ## U, 0x ## hi ## U }
+#else
+#define ULLC(hi,lo) { 0x ## hi ## U, 0x ## lo ## U }
+#endif
+
+#define SHA_HTONLL(x) ( BYTESWAP4(x.lo), BYTESWAP4(x.hi), \
+   x.hi ^= x.lo ^= x.hi ^= x.lo, x)
+#define BYTESWAP8(x)  do { PRUint32 tmp; BYTESWAP4(x.lo); BYTESWAP4(x.hi); \
+   tmp = x.lo; x.lo = x.hi; x.hi = tmp; } while (0)
+#endif
+
+/* SHA-384 and SHA-512 constants, K512. */
+static const PRUint64 K512[80] = {
+#if PR_BYTES_PER_LONG == 8
+     0x428a2f98d728ae22UL ,  0x7137449123ef65cdUL ,
+     0xb5c0fbcfec4d3b2fUL ,  0xe9b5dba58189dbbcUL ,
+     0x3956c25bf348b538UL ,  0x59f111f1b605d019UL ,
+     0x923f82a4af194f9bUL ,  0xab1c5ed5da6d8118UL ,
+     0xd807aa98a3030242UL ,  0x12835b0145706fbeUL ,
+     0x243185be4ee4b28cUL ,  0x550c7dc3d5ffb4e2UL ,
+     0x72be5d74f27b896fUL ,  0x80deb1fe3b1696b1UL ,
+     0x9bdc06a725c71235UL ,  0xc19bf174cf692694UL ,
+     0xe49b69c19ef14ad2UL ,  0xefbe4786384f25e3UL ,
+     0x0fc19dc68b8cd5b5UL ,  0x240ca1cc77ac9c65UL ,
+     0x2de92c6f592b0275UL ,  0x4a7484aa6ea6e483UL ,
+     0x5cb0a9dcbd41fbd4UL ,  0x76f988da831153b5UL ,
+     0x983e5152ee66dfabUL ,  0xa831c66d2db43210UL ,
+     0xb00327c898fb213fUL ,  0xbf597fc7beef0ee4UL ,
+     0xc6e00bf33da88fc2UL ,  0xd5a79147930aa725UL ,
+     0x06ca6351e003826fUL ,  0x142929670a0e6e70UL ,
+     0x27b70a8546d22ffcUL ,  0x2e1b21385c26c926UL ,
+     0x4d2c6dfc5ac42aedUL ,  0x53380d139d95b3dfUL ,
+     0x650a73548baf63deUL ,  0x766a0abb3c77b2a8UL ,
+     0x81c2c92e47edaee6UL ,  0x92722c851482353bUL ,
+     0xa2bfe8a14cf10364UL ,  0xa81a664bbc423001UL ,
+     0xc24b8b70d0f89791UL ,  0xc76c51a30654be30UL ,
+     0xd192e819d6ef5218UL ,  0xd69906245565a910UL ,
+     0xf40e35855771202aUL ,  0x106aa07032bbd1b8UL ,
+     0x19a4c116b8d2d0c8UL ,  0x1e376c085141ab53UL ,
+     0x2748774cdf8eeb99UL ,  0x34b0bcb5e19b48a8UL ,
+     0x391c0cb3c5c95a63UL ,  0x4ed8aa4ae3418acbUL ,
+     0x5b9cca4f7763e373UL ,  0x682e6ff3d6b2b8a3UL ,
+     0x748f82ee5defb2fcUL ,  0x78a5636f43172f60UL ,
+     0x84c87814a1f0ab72UL ,  0x8cc702081a6439ecUL ,
+     0x90befffa23631e28UL ,  0xa4506cebde82bde9UL ,
+     0xbef9a3f7b2c67915UL ,  0xc67178f2e372532bUL ,
+     0xca273eceea26619cUL ,  0xd186b8c721c0c207UL ,
+     0xeada7dd6cde0eb1eUL ,  0xf57d4f7fee6ed178UL ,
+     0x06f067aa72176fbaUL ,  0x0a637dc5a2c898a6UL ,
+     0x113f9804bef90daeUL ,  0x1b710b35131c471bUL ,
+     0x28db77f523047d84UL ,  0x32caab7b40c72493UL ,
+     0x3c9ebe0a15c9bebcUL ,  0x431d67c49c100d4cUL ,
+     0x4cc5d4becb3e42b6UL ,  0x597f299cfc657e2aUL ,
+     0x5fcb6fab3ad6faecUL ,  0x6c44198c4a475817UL
+#else
+    ULLC(428a2f98,d728ae22), ULLC(71374491,23ef65cd),
+    ULLC(b5c0fbcf,ec4d3b2f), ULLC(e9b5dba5,8189dbbc),
+    ULLC(3956c25b,f348b538), ULLC(59f111f1,b605d019),
+    ULLC(923f82a4,af194f9b), ULLC(ab1c5ed5,da6d8118),
+    ULLC(d807aa98,a3030242), ULLC(12835b01,45706fbe),
+    ULLC(243185be,4ee4b28c), ULLC(550c7dc3,d5ffb4e2),
+    ULLC(72be5d74,f27b896f), ULLC(80deb1fe,3b1696b1),
+    ULLC(9bdc06a7,25c71235), ULLC(c19bf174,cf692694),
+    ULLC(e49b69c1,9ef14ad2), ULLC(efbe4786,384f25e3),
+    ULLC(0fc19dc6,8b8cd5b5), ULLC(240ca1cc,77ac9c65),
+    ULLC(2de92c6f,592b0275), ULLC(4a7484aa,6ea6e483),
+    ULLC(5cb0a9dc,bd41fbd4), ULLC(76f988da,831153b5),
+    ULLC(983e5152,ee66dfab), ULLC(a831c66d,2db43210),
+    ULLC(b00327c8,98fb213f), ULLC(bf597fc7,beef0ee4),
+    ULLC(c6e00bf3,3da88fc2), ULLC(d5a79147,930aa725),
+    ULLC(06ca6351,e003826f), ULLC(14292967,0a0e6e70),
+    ULLC(27b70a85,46d22ffc), ULLC(2e1b2138,5c26c926),
+    ULLC(4d2c6dfc,5ac42aed), ULLC(53380d13,9d95b3df),
+    ULLC(650a7354,8baf63de), ULLC(766a0abb,3c77b2a8),
+    ULLC(81c2c92e,47edaee6), ULLC(92722c85,1482353b),
+    ULLC(a2bfe8a1,4cf10364), ULLC(a81a664b,bc423001),
+    ULLC(c24b8b70,d0f89791), ULLC(c76c51a3,0654be30),
+    ULLC(d192e819,d6ef5218), ULLC(d6990624,5565a910),
+    ULLC(f40e3585,5771202a), ULLC(106aa070,32bbd1b8),
+    ULLC(19a4c116,b8d2d0c8), ULLC(1e376c08,5141ab53),
+    ULLC(2748774c,df8eeb99), ULLC(34b0bcb5,e19b48a8),
+    ULLC(391c0cb3,c5c95a63), ULLC(4ed8aa4a,e3418acb),
+    ULLC(5b9cca4f,7763e373), ULLC(682e6ff3,d6b2b8a3),
+    ULLC(748f82ee,5defb2fc), ULLC(78a5636f,43172f60),
+    ULLC(84c87814,a1f0ab72), ULLC(8cc70208,1a6439ec),
+    ULLC(90befffa,23631e28), ULLC(a4506ceb,de82bde9),
+    ULLC(bef9a3f7,b2c67915), ULLC(c67178f2,e372532b),
+    ULLC(ca273ece,ea26619c), ULLC(d186b8c7,21c0c207),
+    ULLC(eada7dd6,cde0eb1e), ULLC(f57d4f7f,ee6ed178),
+    ULLC(06f067aa,72176fba), ULLC(0a637dc5,a2c898a6),
+    ULLC(113f9804,bef90dae), ULLC(1b710b35,131c471b),
+    ULLC(28db77f5,23047d84), ULLC(32caab7b,40c72493),
+    ULLC(3c9ebe0a,15c9bebc), ULLC(431d67c4,9c100d4c),
+    ULLC(4cc5d4be,cb3e42b6), ULLC(597f299c,fc657e2a),
+    ULLC(5fcb6fab,3ad6faec), ULLC(6c44198c,4a475817)
+#endif
+};
+
+struct SHA512ContextStr {
+    union {
+	PRUint64 w[80];	    /* message schedule, input buffer, plus 64 words */
+	PRUint32 l[160];
+	PRUint8  b[640];
+    } u;
+    PRUint64 h[8];	    /* 8 state variables */
+    PRUint64 sizeLo;	    /* 64-bit count of hashed bytes. */
+};
+
+/* =========== SHA512 implementation ===================================== */
+
+/* SHA-512 initial hash values */
+static const PRUint64 H512[8] = {
+#if PR_BYTES_PER_LONG == 8
+     0x6a09e667f3bcc908UL ,  0xbb67ae8584caa73bUL ,
+     0x3c6ef372fe94f82bUL ,  0xa54ff53a5f1d36f1UL ,
+     0x510e527fade682d1UL ,  0x9b05688c2b3e6c1fUL ,
+     0x1f83d9abfb41bd6bUL ,  0x5be0cd19137e2179UL
+#else
+    ULLC(6a09e667,f3bcc908), ULLC(bb67ae85,84caa73b),
+    ULLC(3c6ef372,fe94f82b), ULLC(a54ff53a,5f1d36f1),
+    ULLC(510e527f,ade682d1), ULLC(9b05688c,2b3e6c1f),
+    ULLC(1f83d9ab,fb41bd6b), ULLC(5be0cd19,137e2179)
+#endif
+};
+
+
+SHA512Context *
+SHA512_NewContext(void)
+{
+    SHA512Context *ctx = PORT_New(SHA512Context);
+    return ctx;
+}
+
+void
+SHA512_DestroyContext(SHA512Context *ctx, PRBool freeit)
+{
+    if (freeit) {
+        PORT_ZFree(ctx, sizeof *ctx);
+    }
+}
+
+void
+SHA512_Begin(SHA512Context *ctx)
+{
+    memset(ctx, 0, sizeof *ctx);
+    memcpy(H, H512, sizeof H512);
+}
+
+#if defined(SHA512_TRACE)
+#if defined(HAVE_LONG_LONG)
+#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %016lx, %s = %016lx\n", \
+			       n, #e, d, #a, h);
+#else
+#define DUMP(n,a,d,e,h) printf(" t = %2d, %s = %08x%08x, %s = %08x%08x\n", \
+			       n, #e, d.hi, d.lo, #a, h.hi, h.lo);
+#endif
+#else
+#define DUMP(n,a,d,e,h)
+#endif
+
+#if defined(HAVE_LONG_LONG)
+
+#define ADDTO(x,y) y += x
+
+#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16])
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+    h += S1(e) + Ch(e,f,g) + K512[n] + W[n]; \
+    d += h; \
+    h += S0(a) + Maj(a,b,c); \
+    DUMP(n,a,d,e,h)
+
+#else /* use only 32-bit variables, and don't unroll loops */
+
+#undef  NOUNROLL512
+#define NOUNROLL512 1
+
+#define ADDTO(x,y) y.lo += x.lo; y.hi += x.hi + (x.lo > y.lo)
+
+#define ROTR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
+#define ROTR64A(x,n,lo,hi) (x.lo << (64-n) | x.hi >> (n-32))
+#define  SHR64a(x,n,lo,hi) (x.lo >> n | x.hi << (32-n))
+
+/* Capitol Sigma and lower case sigma functions */
+#define s0lo(x) (ROTR64a(x,1,lo,hi) ^ ROTR64a(x,8,lo,hi) ^ SHR64a(x,7,lo,hi))
+#define s0hi(x) (ROTR64a(x,1,hi,lo) ^ ROTR64a(x,8,hi,lo) ^ (x.hi >> 7))
+
+#define s1lo(x) (ROTR64a(x,19,lo,hi) ^ ROTR64A(x,61,lo,hi) ^ SHR64a(x,6,lo,hi))
+#define s1hi(x) (ROTR64a(x,19,hi,lo) ^ ROTR64A(x,61,hi,lo) ^ (x.hi >> 6))
+
+#define S0lo(x)(ROTR64a(x,28,lo,hi) ^ ROTR64A(x,34,lo,hi) ^ ROTR64A(x,39,lo,hi))
+#define S0hi(x)(ROTR64a(x,28,hi,lo) ^ ROTR64A(x,34,hi,lo) ^ ROTR64A(x,39,hi,lo))
+
+#define S1lo(x)(ROTR64a(x,14,lo,hi) ^ ROTR64a(x,18,lo,hi) ^ ROTR64A(x,41,lo,hi))
+#define S1hi(x)(ROTR64a(x,14,hi,lo) ^ ROTR64a(x,18,hi,lo) ^ ROTR64A(x,41,hi,lo))
+
+/* 32-bit versions of Ch and Maj */
+#define Chxx(x,y,z,lo) ((x.lo & y.lo) ^ (~x.lo & z.lo))
+#define Majx(x,y,z,lo) ((x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo))
+
+#define INITW(t) \
+    do { \
+	PRUint32 lo, tm; \
+	PRUint32 cy = 0; \
+	lo = s1lo(W[t-2]); \
+	lo += (tm = W[t-7].lo);     if (lo < tm) cy++; \
+	lo += (tm = s0lo(W[t-15])); if (lo < tm) cy++; \
+	lo += (tm = W[t-16].lo);    if (lo < tm) cy++; \
+	W[t].lo = lo; \
+	W[t].hi = cy + s1hi(W[t-2]) + W[t-7].hi + s0hi(W[t-15]) + W[t-16].hi; \
+    } while (0)
+
+#define ROUND(n,a,b,c,d,e,f,g,h) \
+    { \
+	PRUint32 lo, tm, cy; \
+	lo  = S1lo(e); \
+	lo += (tm = Chxx(e,f,g,lo));    cy = (lo < tm); \
+	lo += (tm = K512[n].lo);	if (lo < tm) cy++; \
+	lo += (tm =    W[n].lo);	if (lo < tm) cy++; \
+	h.lo += lo;			if (h.lo < lo) cy++; \
+	h.hi += cy + S1hi(e) + Chxx(e,f,g,hi) + K512[n].hi + W[n].hi; \
+	d.lo += h.lo; \
+	d.hi += h.hi + (d.lo < h.lo); \
+	lo  = S0lo(a);  \
+	lo += (tm = Majx(a,b,c,lo));	cy = (lo < tm); \
+	h.lo += lo;			if (h.lo < lo) cy++; \
+	h.hi += cy + S0hi(a) + Majx(a,b,c,hi); \
+	DUMP(n,a,d,e,h) \
+    }
+#endif
+
+static void
+SHA512_Compress(SHA512Context *ctx)
+{
+#if defined(IS_LITTLE_ENDIAN)
+  {
+#if defined(HAVE_LONG_LONG)
+    PRUint64 t1;
+#else
+    PRUint32 t1;
+#endif
+    BYTESWAP8(W[0]);
+    BYTESWAP8(W[1]);
+    BYTESWAP8(W[2]);
+    BYTESWAP8(W[3]);
+    BYTESWAP8(W[4]);
+    BYTESWAP8(W[5]);
+    BYTESWAP8(W[6]);
+    BYTESWAP8(W[7]);
+    BYTESWAP8(W[8]);
+    BYTESWAP8(W[9]);
+    BYTESWAP8(W[10]);
+    BYTESWAP8(W[11]);
+    BYTESWAP8(W[12]);
+    BYTESWAP8(W[13]);
+    BYTESWAP8(W[14]);
+    BYTESWAP8(W[15]);
+  }
+#endif
+
+  {
+    PRUint64 t1, t2;
+#ifdef NOUNROLL512
+    {
+	/* prepare the "message schedule"   */
+	int t;
+	for (t = 16; t < 80; ++t) {
+	    INITW(t);
+	}
+    }
+#else
+    INITW(16);
+    INITW(17);
+    INITW(18);
+    INITW(19);
+
+    INITW(20);
+    INITW(21);
+    INITW(22);
+    INITW(23);
+    INITW(24);
+    INITW(25);
+    INITW(26);
+    INITW(27);
+    INITW(28);
+    INITW(29);
+
+    INITW(30);
+    INITW(31);
+    INITW(32);
+    INITW(33);
+    INITW(34);
+    INITW(35);
+    INITW(36);
+    INITW(37);
+    INITW(38);
+    INITW(39);
+
+    INITW(40);
+    INITW(41);
+    INITW(42);
+    INITW(43);
+    INITW(44);
+    INITW(45);
+    INITW(46);
+    INITW(47);
+    INITW(48);
+    INITW(49);
+
+    INITW(50);
+    INITW(51);
+    INITW(52);
+    INITW(53);
+    INITW(54);
+    INITW(55);
+    INITW(56);
+    INITW(57);
+    INITW(58);
+    INITW(59);
+
+    INITW(60);
+    INITW(61);
+    INITW(62);
+    INITW(63);
+    INITW(64);
+    INITW(65);
+    INITW(66);
+    INITW(67);
+    INITW(68);
+    INITW(69);
+
+    INITW(70);
+    INITW(71);
+    INITW(72);
+    INITW(73);
+    INITW(74);
+    INITW(75);
+    INITW(76);
+    INITW(77);
+    INITW(78);
+    INITW(79);
+#endif
+  }
+#ifdef SHA512_TRACE
+  {
+    int i;
+    for (i = 0; i < 80; ++i) {
+#ifdef HAVE_LONG_LONG
+	printf("W[%2d] = %016lx\n", i, W[i]);
+#else
+	printf("W[%2d] = %08x%08x\n", i, W[i].hi, W[i].lo);
+#endif
+    }
+  }
+#endif
+  {
+    PRUint64 a, b, c, d, e, f, g, h;
+
+    a = H[0];
+    b = H[1];
+    c = H[2];
+    d = H[3];
+    e = H[4];
+    f = H[5];
+    g = H[6];
+    h = H[7];
+
+#ifdef NOUNROLL512
+    {
+	int t;
+	for (t = 0; t < 80; t+= 8) {
+	    ROUND(t+0,a,b,c,d,e,f,g,h)
+	    ROUND(t+1,h,a,b,c,d,e,f,g)
+	    ROUND(t+2,g,h,a,b,c,d,e,f)
+	    ROUND(t+3,f,g,h,a,b,c,d,e)
+	    ROUND(t+4,e,f,g,h,a,b,c,d)
+	    ROUND(t+5,d,e,f,g,h,a,b,c)
+	    ROUND(t+6,c,d,e,f,g,h,a,b)
+	    ROUND(t+7,b,c,d,e,f,g,h,a)
+	}
+    }
+#else
+    ROUND( 0,a,b,c,d,e,f,g,h)
+    ROUND( 1,h,a,b,c,d,e,f,g)
+    ROUND( 2,g,h,a,b,c,d,e,f)
+    ROUND( 3,f,g,h,a,b,c,d,e)
+    ROUND( 4,e,f,g,h,a,b,c,d)
+    ROUND( 5,d,e,f,g,h,a,b,c)
+    ROUND( 6,c,d,e,f,g,h,a,b)
+    ROUND( 7,b,c,d,e,f,g,h,a)
+
+    ROUND( 8,a,b,c,d,e,f,g,h)
+    ROUND( 9,h,a,b,c,d,e,f,g)
+    ROUND(10,g,h,a,b,c,d,e,f)
+    ROUND(11,f,g,h,a,b,c,d,e)
+    ROUND(12,e,f,g,h,a,b,c,d)
+    ROUND(13,d,e,f,g,h,a,b,c)
+    ROUND(14,c,d,e,f,g,h,a,b)
+    ROUND(15,b,c,d,e,f,g,h,a)
+
+    ROUND(16,a,b,c,d,e,f,g,h)
+    ROUND(17,h,a,b,c,d,e,f,g)
+    ROUND(18,g,h,a,b,c,d,e,f)
+    ROUND(19,f,g,h,a,b,c,d,e)
+    ROUND(20,e,f,g,h,a,b,c,d)
+    ROUND(21,d,e,f,g,h,a,b,c)
+    ROUND(22,c,d,e,f,g,h,a,b)
+    ROUND(23,b,c,d,e,f,g,h,a)
+
+    ROUND(24,a,b,c,d,e,f,g,h)
+    ROUND(25,h,a,b,c,d,e,f,g)
+    ROUND(26,g,h,a,b,c,d,e,f)
+    ROUND(27,f,g,h,a,b,c,d,e)
+    ROUND(28,e,f,g,h,a,b,c,d)
+    ROUND(29,d,e,f,g,h,a,b,c)
+    ROUND(30,c,d,e,f,g,h,a,b)
+    ROUND(31,b,c,d,e,f,g,h,a)
+
+    ROUND(32,a,b,c,d,e,f,g,h)
+    ROUND(33,h,a,b,c,d,e,f,g)
+    ROUND(34,g,h,a,b,c,d,e,f)
+    ROUND(35,f,g,h,a,b,c,d,e)
+    ROUND(36,e,f,g,h,a,b,c,d)
+    ROUND(37,d,e,f,g,h,a,b,c)
+    ROUND(38,c,d,e,f,g,h,a,b)
+    ROUND(39,b,c,d,e,f,g,h,a)
+
+    ROUND(40,a,b,c,d,e,f,g,h)
+    ROUND(41,h,a,b,c,d,e,f,g)
+    ROUND(42,g,h,a,b,c,d,e,f)
+    ROUND(43,f,g,h,a,b,c,d,e)
+    ROUND(44,e,f,g,h,a,b,c,d)
+    ROUND(45,d,e,f,g,h,a,b,c)
+    ROUND(46,c,d,e,f,g,h,a,b)
+    ROUND(47,b,c,d,e,f,g,h,a)
+
+    ROUND(48,a,b,c,d,e,f,g,h)
+    ROUND(49,h,a,b,c,d,e,f,g)
+    ROUND(50,g,h,a,b,c,d,e,f)
+    ROUND(51,f,g,h,a,b,c,d,e)
+    ROUND(52,e,f,g,h,a,b,c,d)
+    ROUND(53,d,e,f,g,h,a,b,c)
+    ROUND(54,c,d,e,f,g,h,a,b)
+    ROUND(55,b,c,d,e,f,g,h,a)
+
+    ROUND(56,a,b,c,d,e,f,g,h)
+    ROUND(57,h,a,b,c,d,e,f,g)
+    ROUND(58,g,h,a,b,c,d,e,f)
+    ROUND(59,f,g,h,a,b,c,d,e)
+    ROUND(60,e,f,g,h,a,b,c,d)
+    ROUND(61,d,e,f,g,h,a,b,c)
+    ROUND(62,c,d,e,f,g,h,a,b)
+    ROUND(63,b,c,d,e,f,g,h,a)
+
+    ROUND(64,a,b,c,d,e,f,g,h)
+    ROUND(65,h,a,b,c,d,e,f,g)
+    ROUND(66,g,h,a,b,c,d,e,f)
+    ROUND(67,f,g,h,a,b,c,d,e)
+    ROUND(68,e,f,g,h,a,b,c,d)
+    ROUND(69,d,e,f,g,h,a,b,c)
+    ROUND(70,c,d,e,f,g,h,a,b)
+    ROUND(71,b,c,d,e,f,g,h,a)
+
+    ROUND(72,a,b,c,d,e,f,g,h)
+    ROUND(73,h,a,b,c,d,e,f,g)
+    ROUND(74,g,h,a,b,c,d,e,f)
+    ROUND(75,f,g,h,a,b,c,d,e)
+    ROUND(76,e,f,g,h,a,b,c,d)
+    ROUND(77,d,e,f,g,h,a,b,c)
+    ROUND(78,c,d,e,f,g,h,a,b)
+    ROUND(79,b,c,d,e,f,g,h,a)
+#endif
+
+    ADDTO(a,H[0]);
+    ADDTO(b,H[1]);
+    ADDTO(c,H[2]);
+    ADDTO(d,H[3]);
+    ADDTO(e,H[4]);
+    ADDTO(f,H[5]);
+    ADDTO(g,H[6]);
+    ADDTO(h,H[7]);
+  }
+}
+
+void
+SHA512_Update(SHA512Context *ctx, const unsigned char *input,
+              unsigned int inputLen)
+{
+    unsigned int inBuf;
+    if (!inputLen)
+    	return;
+
+#if defined(HAVE_LONG_LONG)
+    inBuf = (unsigned int)ctx->sizeLo & 0x7f;
+    /* Add inputLen into the count of bytes processed, before processing */
+    ctx->sizeLo += inputLen;
+#else
+    inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f;
+    ctx->sizeLo.lo += inputLen;
+    if (ctx->sizeLo.lo < inputLen) ctx->sizeLo.hi++;
+#endif
+
+    /* if data already in buffer, attemp to fill rest of buffer */
+    if (inBuf) {
+    	unsigned int todo = SHA512_BLOCK_LENGTH - inBuf;
+	if (inputLen < todo)
+	    todo = inputLen;
+	memcpy(B + inBuf, input, todo);
+	input    += todo;
+	inputLen -= todo;
+	if (inBuf + todo == SHA512_BLOCK_LENGTH)
+	    SHA512_Compress(ctx);
+    }
+
+    /* if enough data to fill one or more whole buffers, process them. */
+    while (inputLen >= SHA512_BLOCK_LENGTH) {
+    	memcpy(B, input, SHA512_BLOCK_LENGTH);
+	input    += SHA512_BLOCK_LENGTH;
+	inputLen -= SHA512_BLOCK_LENGTH;
+	SHA512_Compress(ctx);
+    }
+    /* if data left over, fill it into buffer */
+    if (inputLen)
+    	memcpy(B, input, inputLen);
+}
+
+void
+SHA512_End(SHA512Context *ctx, unsigned char *digest,
+           unsigned int *digestLen, unsigned int maxDigestLen)
+{
+#if defined(HAVE_LONG_LONG)
+    unsigned int inBuf  = (unsigned int)ctx->sizeLo & 0x7f;
+    unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf);
+    PRUint64 lo, t1;
+    lo = (ctx->sizeLo << 3);
+#else
+    unsigned int inBuf  = (unsigned int)ctx->sizeLo.lo & 0x7f;
+    unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf);
+    PRUint64 lo = ctx->sizeLo;
+    PRUint32 t1;
+    lo.lo <<= 3;
+#endif
+
+    SHA512_Update(ctx, pad, padLen);
+
+#if defined(HAVE_LONG_LONG)
+    W[14] = 0;
+#else
+    W[14].lo = 0;
+    W[14].hi = 0;
+#endif
+
+    W[15] = lo;
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP8(W[15]);
+#endif
+    SHA512_Compress(ctx);
+
+    /* now output the answer */
+#if defined(IS_LITTLE_ENDIAN)
+    BYTESWAP8(H[0]);
+    BYTESWAP8(H[1]);
+    BYTESWAP8(H[2]);
+    BYTESWAP8(H[3]);
+    BYTESWAP8(H[4]);
+    BYTESWAP8(H[5]);
+    BYTESWAP8(H[6]);
+    BYTESWAP8(H[7]);
+#endif
+    padLen = PR_MIN(SHA512_LENGTH, maxDigestLen);
+    memcpy(digest, H, padLen);
+    if (digestLen)
+	*digestLen = padLen;
+}
+
+SECStatus
+SHA512_HashBuf(unsigned char *dest, const unsigned char *src,
+               unsigned int src_length)
+{
+    SHA512Context ctx;
+    unsigned int outLen;
+
+    SHA512_Begin(&ctx);
+    SHA512_Update(&ctx, src, src_length);
+    SHA512_End(&ctx, dest, &outLen, SHA512_LENGTH);
+
+    return SECSuccess;
+}
+
+
+SECStatus
+SHA512_Hash(unsigned char *dest, const char *src)
+{
+    return SHA512_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+
+void SHA512_TraceState(SHA512Context *ctx) { }
+
+unsigned int
+SHA512_FlattenSize(SHA512Context *ctx)
+{
+    return sizeof *ctx;
+}
+
+SECStatus
+SHA512_Flatten(SHA512Context *ctx,unsigned char *space)
+{
+    PORT_Memcpy(space, ctx, sizeof *ctx);
+    return SECSuccess;
+}
+
+SHA512Context *
+SHA512_Resurrect(unsigned char *space, void *arg)
+{
+    SHA512Context *ctx = SHA512_NewContext();
+    if (ctx)
+	PORT_Memcpy(ctx, space, sizeof *ctx);
+    return ctx;
+}
+
+void SHA512_Clone(SHA512Context *dest, SHA512Context *src)
+{
+    memcpy(dest, src, sizeof *dest);
+}
+
+/* ======================================================================= */
+/* SHA384 uses a SHA512Context as the real context.
+** The only differences between SHA384 an SHA512 are:
+** a) the intialization values for the context, and
+** b) the number of bytes of data produced as output.
+*/
+
+/* SHA-384 initial hash values */
+static const PRUint64 H384[8] = {
+#if PR_BYTES_PER_LONG == 8
+     0xcbbb9d5dc1059ed8UL ,  0x629a292a367cd507UL ,
+     0x9159015a3070dd17UL ,  0x152fecd8f70e5939UL ,
+     0x67332667ffc00b31UL ,  0x8eb44a8768581511UL ,
+     0xdb0c2e0d64f98fa7UL ,  0x47b5481dbefa4fa4UL
+#else
+    ULLC(cbbb9d5d,c1059ed8), ULLC(629a292a,367cd507),
+    ULLC(9159015a,3070dd17), ULLC(152fecd8,f70e5939),
+    ULLC(67332667,ffc00b31), ULLC(8eb44a87,68581511),
+    ULLC(db0c2e0d,64f98fa7), ULLC(47b5481d,befa4fa4)
+#endif
+};
+
+SHA384Context *
+SHA384_NewContext(void)
+{
+    return SHA512_NewContext();
+}
+
+void
+SHA384_DestroyContext(SHA384Context *ctx, PRBool freeit)
+{
+    SHA512_DestroyContext(ctx, freeit);
+}
+
+void
+SHA384_Begin(SHA384Context *ctx)
+{
+    memset(ctx, 0, sizeof *ctx);
+    memcpy(H, H384, sizeof H384);
+}
+
+void
+SHA384_Update(SHA384Context *ctx, const unsigned char *input,
+		    unsigned int inputLen)
+{
+    SHA512_Update(ctx, input, inputLen);
+}
+
+void
+SHA384_End(SHA384Context *ctx, unsigned char *digest,
+		 unsigned int *digestLen, unsigned int maxDigestLen)
+{
+#define SHA_MIN(a,b) (a < b ? a : b)
+    unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH);
+    SHA512_End(ctx, digest, digestLen, maxLen);
+}
+
+SECStatus
+SHA384_HashBuf(unsigned char *dest, const unsigned char *src,
+			  unsigned int src_length)
+{
+    SHA512Context ctx;
+    unsigned int outLen;
+
+    SHA384_Begin(&ctx);
+    SHA512_Update(&ctx, src, src_length);
+    SHA512_End(&ctx, dest, &outLen, SHA384_LENGTH);
+
+    return SECSuccess;
+}
+
+SECStatus
+SHA384_Hash(unsigned char *dest, const char *src)
+{
+    return SHA384_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
+}
+
+void SHA384_TraceState(SHA384Context *ctx) { }
+
+unsigned int
+SHA384_FlattenSize(SHA384Context *ctx)
+{
+    return sizeof(SHA384Context);
+}
+
+SECStatus
+SHA384_Flatten(SHA384Context *ctx,unsigned char *space)
+{
+    return SHA512_Flatten(ctx, space);
+}
+
+SHA384Context *
+SHA384_Resurrect(unsigned char *space, void *arg)
+{
+    return SHA512_Resurrect(space, arg);
+}
+
+void SHA384_Clone(SHA384Context *dest, SHA384Context *src)
+{
+    memcpy(dest, src, sizeof *dest);
+}
+#endif  /* Comment out unused code. */
+
+/* ======================================================================= */
+#ifdef SELFTEST
+#include <stdio.h>
+
+static const char abc[] = { "abc" };
+static const char abcdbc[] = {
+    "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+};
+static const char abcdef[] = {
+    "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+    "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+};
+
+void
+dumpHash32(const unsigned char *buf, unsigned int bufLen)
+{
+    unsigned int i;
+    for (i = 0; i < bufLen; i += 4) {
+	printf(" %02x%02x%02x%02x", buf[i], buf[i+1], buf[i+2], buf[i+3]);
+    }
+    printf("\n");
+}
+
+void test256(void)
+{
+    unsigned char outBuf[SHA256_LENGTH];
+
+    printf("SHA256, input = %s\n", abc);
+    SHA256_Hash(outBuf, abc);
+    dumpHash32(outBuf, sizeof outBuf);
+
+    printf("SHA256, input = %s\n", abcdbc);
+    SHA256_Hash(outBuf, abcdbc);
+    dumpHash32(outBuf, sizeof outBuf);
+}
+
+void
+dumpHash64(const unsigned char *buf, unsigned int bufLen)
+{
+    unsigned int i;
+    for (i = 0; i < bufLen; i += 8) {
+    	if (i % 32 == 0)
+	    printf("\n");
+	printf(" %02x%02x%02x%02x%02x%02x%02x%02x",
+	       buf[i  ], buf[i+1], buf[i+2], buf[i+3],
+	       buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
+    }
+    printf("\n");
+}
+
+void test512(void)
+{
+    unsigned char outBuf[SHA512_LENGTH];
+
+    printf("SHA512, input = %s\n", abc);
+    SHA512_Hash(outBuf, abc);
+    dumpHash64(outBuf, sizeof outBuf);
+
+    printf("SHA512, input = %s\n", abcdef);
+    SHA512_Hash(outBuf, abcdef);
+    dumpHash64(outBuf, sizeof outBuf);
+}
+
+void time512(void)
+{
+    unsigned char outBuf[SHA512_LENGTH];
+
+    SHA512_Hash(outBuf, abc);
+    SHA512_Hash(outBuf, abcdef);
+}
+
+void test384(void)
+{
+    unsigned char outBuf[SHA384_LENGTH];
+
+    printf("SHA384, input = %s\n", abc);
+    SHA384_Hash(outBuf, abc);
+    dumpHash64(outBuf, sizeof outBuf);
+
+    printf("SHA384, input = %s\n", abcdef);
+    SHA384_Hash(outBuf, abcdef);
+    dumpHash64(outBuf, sizeof outBuf);
+}
+
+int main (int argc, char *argv[], char *envp[])
+{
+    int i = 1;
+    if (argc > 1) {
+    	i = atoi(argv[1]);
+    }
+    if (i < 2) {
+	test256();
+	test512();
+	test384();
+    } else {
+    	while (i-- > 0) {
+	    time512();
+	}
+	printf("done\n");
+    }
+    return 0;
+}
+
+#endif
diff --git a/libchrome/crypto/wincrypt_shim.h b/libchrome/crypto/wincrypt_shim.h
new file mode 100644
index 0000000..48d4b5c
--- /dev/null
+++ b/libchrome/crypto/wincrypt_shim.h
@@ -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.
+
+#ifndef NET_CRYPTO_WINCRYPT_SHIM_H_
+#define NET_CRYPTO_WINCRYPT_SHIM_H_
+
+// wincrypt.h defines macros which conflict with OpenSSL's types. This header
+// includes wincrypt and undefines the OpenSSL macros which conflict. Any
+// Chromium headers which include wincrypt should instead include this header.
+
+#include <windows.h>
+#include <wincrypt.h>
+
+// Undefine the macros which conflict with OpenSSL and define replacements. See
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa378145(v=vs.85).aspx
+#undef X509_CERT_PAIR
+#undef X509_EXTENSIONS
+#undef X509_NAME
+
+#define WINCRYPT_X509_CERT_PAIR ((LPCSTR) 53)
+#define WINCRYPT_X509_EXTENSIONS ((LPCSTR) 5)
+#define WINCRYPT_X509_NAME ((LPCSTR) 7)
+
+#endif  // NET_CRYPTO_WINCRYPT_SHIM_H_
diff --git a/libchrome/dbus/BUILD.gn b/libchrome/dbus/BUILD.gn
new file mode 100644
index 0000000..28efb93
--- /dev/null
+++ b/libchrome/dbus/BUILD.gn
@@ -0,0 +1,134 @@
+# 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/features.gni")
+import("//testing/test.gni")
+import("//third_party/protobuf/proto_library.gni")
+
+assert(use_dbus)
+
+component("dbus") {
+  sources = [
+    "bus.cc",
+    "bus.h",
+    "dbus_export.h",
+    "dbus_statistics.cc",
+    "dbus_statistics.h",
+    "exported_object.cc",
+    "exported_object.h",
+    "file_descriptor.cc",
+    "file_descriptor.h",
+    "message.cc",
+    "message.h",
+    "object_manager.cc",
+    "object_manager.h",
+    "object_path.cc",
+    "object_path.h",
+    "object_proxy.cc",
+    "object_proxy.h",
+    "property.cc",
+    "property.h",
+    "scoped_dbus_error.cc",
+    "scoped_dbus_error.h",
+    "string_util.cc",
+    "string_util.h",
+    "util.cc",
+    "util.h",
+    "values_util.cc",
+    "values_util.h",
+  ]
+
+  defines = [ "DBUS_IMPLEMENTATION" ]
+
+  deps = [
+    "//third_party/protobuf:protobuf_lite",
+  ]
+  public_deps = [
+    "//base",
+  ]
+
+  public_configs = [ "//build/config/linux/dbus" ]
+}
+
+proto_library("test_proto") {
+  sources = [
+    "test_proto.proto",
+  ]
+}
+
+# This target contains mocks that can be used to write unit tests without
+# issuing actual D-Bus calls.
+static_library("test_support") {
+  testonly = true
+  sources = [
+    "mock_bus.cc",
+    "mock_bus.h",
+    "mock_exported_object.cc",
+    "mock_exported_object.h",
+    "mock_object_manager.cc",
+    "mock_object_manager.h",
+    "mock_object_proxy.cc",
+    "mock_object_proxy.h",
+  ]
+
+  public_deps = [
+    ":dbus",
+  ]
+  deps = [
+    "//testing/gmock",
+  ]
+
+  configs += [ "//build/config/linux/dbus" ]
+}
+
+test("dbus_unittests") {
+  sources = [
+    "bus_unittest.cc",
+    "dbus_statistics_unittest.cc",
+    "end_to_end_async_unittest.cc",
+    "end_to_end_sync_unittest.cc",
+    "message_unittest.cc",
+    "mock_unittest.cc",
+    "object_manager_unittest.cc",
+    "object_proxy_unittest.cc",
+    "property_unittest.cc",
+    "signal_sender_verification_unittest.cc",
+    "string_util_unittest.cc",
+    "test_service.cc",
+    "test_service.h",
+    "util_unittest.cc",
+    "values_util_unittest.cc",
+  ]
+
+  deps = [
+    ":dbus",
+    ":test_proto",
+    ":test_support",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/protobuf:protobuf_lite",
+  ]
+
+  configs += [ "//build/config/linux/dbus" ]
+}
+
+executable("dbus_test_server") {
+  testonly = true
+  sources = [
+    "test_server.cc",
+    "test_service.cc",
+    "test_service.h",
+  ]
+
+  deps = [
+    ":dbus",
+    "//base",
+    "//base/test:test_support",
+    "//build/config/sanitizers:deps",
+  ]
+
+  configs += [ "//build/config/linux/dbus" ]
+}
diff --git a/libchrome/dbus/DEPS b/libchrome/dbus/DEPS
new file mode 100644
index 0000000..97db67c
--- /dev/null
+++ b/libchrome/dbus/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/protobuf",
+]
diff --git a/libchrome/dbus/OWNERS b/libchrome/dbus/OWNERS
new file mode 100644
index 0000000..04931c3
--- /dev/null
+++ b/libchrome/dbus/OWNERS
@@ -0,0 +1,3 @@
+hashimoto@chromium.org
+satorux@chromium.org
+stevenjb@chromium.org
diff --git a/libchrome/dbus/bus.cc b/libchrome/dbus/bus.cc
new file mode 100644
index 0000000..57834d3
--- /dev/null
+++ b/libchrome/dbus/bus.cc
@@ -0,0 +1,1198 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/bus.h"
+
+#include <stddef.h>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "dbus/exported_object.h"
+#include "dbus/message.h"
+#include "dbus/object_manager.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "dbus/scoped_dbus_error.h"
+
+namespace dbus {
+
+namespace {
+
+// The NameOwnerChanged member in org.freedesktop.DBus
+const char kNameOwnerChangedSignal[] = "NameOwnerChanged";
+
+// The match rule used to filter for changes to a given service name owner.
+const char kServiceNameOwnerChangeMatchRule[] =
+    "type='signal',interface='org.freedesktop.DBus',"
+    "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
+    "sender='org.freedesktop.DBus',arg0='%s'";
+
+// The class is used for watching the file descriptor used for D-Bus
+// communication.
+class Watch : public base::MessagePumpLibevent::Watcher {
+ public:
+  explicit Watch(DBusWatch* watch)
+      : raw_watch_(watch) {
+    dbus_watch_set_data(raw_watch_, this, NULL);
+  }
+
+  ~Watch() override { dbus_watch_set_data(raw_watch_, NULL, NULL); }
+
+  // Returns true if the underlying file descriptor is ready to be watched.
+  bool IsReadyToBeWatched() {
+    return dbus_watch_get_enabled(raw_watch_);
+  }
+
+  // Starts watching the underlying file descriptor.
+  void StartWatching() {
+    const int file_descriptor = dbus_watch_get_unix_fd(raw_watch_);
+    const int flags = dbus_watch_get_flags(raw_watch_);
+
+    base::MessageLoopForIO::Mode mode = base::MessageLoopForIO::WATCH_READ;
+    if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE))
+      mode = base::MessageLoopForIO::WATCH_READ_WRITE;
+    else if (flags & DBUS_WATCH_READABLE)
+      mode = base::MessageLoopForIO::WATCH_READ;
+    else if (flags & DBUS_WATCH_WRITABLE)
+      mode = base::MessageLoopForIO::WATCH_WRITE;
+    else
+      NOTREACHED();
+
+    const bool persistent = true;  // Watch persistently.
+    const bool success = base::MessageLoopForIO::current()->WatchFileDescriptor(
+        file_descriptor, persistent, mode, &file_descriptor_watcher_, this);
+    CHECK(success) << "Unable to allocate memory";
+  }
+
+  // Stops watching the underlying file descriptor.
+  void StopWatching() {
+    file_descriptor_watcher_.StopWatchingFileDescriptor();
+  }
+
+ private:
+  // Implement MessagePumpLibevent::Watcher.
+  void OnFileCanReadWithoutBlocking(int /*file_descriptor*/) override {
+    const bool success = dbus_watch_handle(raw_watch_, DBUS_WATCH_READABLE);
+    CHECK(success) << "Unable to allocate memory";
+  }
+
+  // Implement MessagePumpLibevent::Watcher.
+  void OnFileCanWriteWithoutBlocking(int /*file_descriptor*/) override {
+    const bool success = dbus_watch_handle(raw_watch_, DBUS_WATCH_WRITABLE);
+    CHECK(success) << "Unable to allocate memory";
+  }
+
+  DBusWatch* raw_watch_;
+  base::MessagePumpLibevent::FileDescriptorWatcher file_descriptor_watcher_;
+};
+
+// The class is used for monitoring the timeout used for D-Bus method
+// calls.
+//
+// Unlike Watch, Timeout is a ref counted object, to ensure that |this| of
+// the object is is alive when HandleTimeout() is called. It's unlikely
+// but it may be possible that HandleTimeout() is called after
+// Bus::OnRemoveTimeout(). That's why we don't simply delete the object in
+// Bus::OnRemoveTimeout().
+class Timeout : public base::RefCountedThreadSafe<Timeout> {
+ public:
+  explicit Timeout(DBusTimeout* timeout)
+      : raw_timeout_(timeout),
+        monitoring_is_active_(false),
+        is_completed(false) {
+    dbus_timeout_set_data(raw_timeout_, this, NULL);
+    AddRef();  // Balanced on Complete().
+  }
+
+  // Returns true if the timeout is ready to be monitored.
+  bool IsReadyToBeMonitored() {
+    return dbus_timeout_get_enabled(raw_timeout_);
+  }
+
+  // Starts monitoring the timeout.
+  void StartMonitoring(Bus* bus) {
+    bus->GetDBusTaskRunner()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&Timeout::HandleTimeout, this),
+        GetInterval());
+    monitoring_is_active_ = true;
+  }
+
+  // Stops monitoring the timeout.
+  void StopMonitoring() {
+    // We cannot take back the delayed task we posted in
+    // StartMonitoring(), so we just mark the monitoring is inactive now.
+    monitoring_is_active_ = false;
+  }
+
+  // Returns the interval.
+  base::TimeDelta GetInterval() {
+    return base::TimeDelta::FromMilliseconds(
+        dbus_timeout_get_interval(raw_timeout_));
+  }
+
+  // Cleans up the raw_timeout and marks that timeout is completed.
+  // See the class comment above for why we are doing this.
+  void Complete() {
+    dbus_timeout_set_data(raw_timeout_, NULL, NULL);
+    is_completed = true;
+    Release();
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<Timeout>;
+  ~Timeout() {
+  }
+
+  // Handles the timeout.
+  void HandleTimeout() {
+    // If the timeout is marked completed, we should do nothing. This can
+    // occur if this function is called after Bus::OnRemoveTimeout().
+    if (is_completed)
+      return;
+    // Skip if monitoring is canceled.
+    if (!monitoring_is_active_)
+      return;
+
+    const bool success = dbus_timeout_handle(raw_timeout_);
+    CHECK(success) << "Unable to allocate memory";
+  }
+
+  DBusTimeout* raw_timeout_;
+  bool monitoring_is_active_;
+  bool is_completed;
+};
+
+}  // namespace
+
+Bus::Options::Options()
+  : bus_type(SESSION),
+    connection_type(PRIVATE) {
+}
+
+Bus::Options::~Options() {
+}
+
+Bus::Bus(const Options& options)
+    : bus_type_(options.bus_type),
+      connection_type_(options.connection_type),
+      dbus_task_runner_(options.dbus_task_runner),
+      on_shutdown_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+                   base::WaitableEvent::InitialState::NOT_SIGNALED),
+      connection_(NULL),
+      origin_thread_id_(base::PlatformThread::CurrentId()),
+      async_operations_set_up_(false),
+      shutdown_completed_(false),
+      num_pending_watches_(0),
+      num_pending_timeouts_(0),
+      address_(options.address) {
+  // This is safe to call multiple times.
+  dbus_threads_init_default();
+  // The origin message loop is unnecessary if the client uses synchronous
+  // functions only.
+  if (base::ThreadTaskRunnerHandle::IsSet())
+    origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+}
+
+Bus::~Bus() {
+  DCHECK(!connection_);
+  DCHECK(owned_service_names_.empty());
+  DCHECK(match_rules_added_.empty());
+  DCHECK(filter_functions_added_.empty());
+  DCHECK(registered_object_paths_.empty());
+  DCHECK_EQ(0, num_pending_watches_);
+  // TODO(satorux): This check fails occasionally in browser_tests for tests
+  // that run very quickly. Perhaps something does not have time to clean up.
+  // Despite the check failing, the tests seem to run fine. crosbug.com/23416
+  // DCHECK_EQ(0, num_pending_timeouts_);
+}
+
+ObjectProxy* Bus::GetObjectProxy(const std::string& service_name,
+                                 const ObjectPath& object_path) {
+  return GetObjectProxyWithOptions(service_name, object_path,
+                                   ObjectProxy::DEFAULT_OPTIONS);
+}
+
+ObjectProxy* Bus::GetObjectProxyWithOptions(const std::string& service_name,
+                                            const ObjectPath& object_path,
+                                            int options) {
+  AssertOnOriginThread();
+
+  // Check if we already have the requested object proxy.
+  const ObjectProxyTable::key_type key(service_name + object_path.value(),
+                                       options);
+  ObjectProxyTable::iterator iter = object_proxy_table_.find(key);
+  if (iter != object_proxy_table_.end()) {
+    return iter->second.get();
+  }
+
+  scoped_refptr<ObjectProxy> object_proxy =
+      new ObjectProxy(this, service_name, object_path, options);
+  object_proxy_table_[key] = object_proxy;
+
+  return object_proxy.get();
+}
+
+bool Bus::RemoveObjectProxy(const std::string& service_name,
+                            const ObjectPath& object_path,
+                            const base::Closure& callback) {
+  return RemoveObjectProxyWithOptions(service_name, object_path,
+                                      ObjectProxy::DEFAULT_OPTIONS,
+                                      callback);
+}
+
+bool Bus::RemoveObjectProxyWithOptions(const std::string& service_name,
+                                       const ObjectPath& object_path,
+                                       int options,
+                                       const base::Closure& callback) {
+  AssertOnOriginThread();
+
+  // Check if we have the requested object proxy.
+  const ObjectProxyTable::key_type key(service_name + object_path.value(),
+                                       options);
+  ObjectProxyTable::iterator iter = object_proxy_table_.find(key);
+  if (iter != object_proxy_table_.end()) {
+    scoped_refptr<ObjectProxy> object_proxy = iter->second;
+    object_proxy_table_.erase(iter);
+    // Object is present. Remove it now and Detach on the DBus thread.
+    GetDBusTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&Bus::RemoveObjectProxyInternal,
+                   this, object_proxy, callback));
+    return true;
+  }
+  return false;
+}
+
+void Bus::RemoveObjectProxyInternal(scoped_refptr<ObjectProxy> object_proxy,
+                                    const base::Closure& callback) {
+  AssertOnDBusThread();
+
+  object_proxy.get()->Detach();
+
+  GetOriginTaskRunner()->PostTask(FROM_HERE, callback);
+}
+
+ExportedObject* Bus::GetExportedObject(const ObjectPath& object_path) {
+  AssertOnOriginThread();
+
+  // Check if we already have the requested exported object.
+  ExportedObjectTable::iterator iter = exported_object_table_.find(object_path);
+  if (iter != exported_object_table_.end()) {
+    return iter->second.get();
+  }
+
+  scoped_refptr<ExportedObject> exported_object =
+      new ExportedObject(this, object_path);
+  exported_object_table_[object_path] = exported_object;
+
+  return exported_object.get();
+}
+
+void Bus::UnregisterExportedObject(const ObjectPath& object_path) {
+  AssertOnOriginThread();
+
+  // Remove the registered object from the table first, to allow a new
+  // GetExportedObject() call to return a new object, rather than this one.
+  ExportedObjectTable::iterator iter = exported_object_table_.find(object_path);
+  if (iter == exported_object_table_.end())
+    return;
+
+  scoped_refptr<ExportedObject> exported_object = iter->second;
+  exported_object_table_.erase(iter);
+
+  // Post the task to perform the final unregistration to the D-Bus thread.
+  // Since the registration also happens on the D-Bus thread in
+  // TryRegisterObjectPath(), and the task runner we post to is a
+  // SequencedTaskRunner, there is a guarantee that this will happen before any
+  // future registration call.
+  GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::UnregisterExportedObjectInternal,
+                 this, exported_object));
+}
+
+void Bus::UnregisterExportedObjectInternal(
+    scoped_refptr<ExportedObject> exported_object) {
+  AssertOnDBusThread();
+
+  exported_object->Unregister();
+}
+
+ObjectManager* Bus::GetObjectManager(const std::string& service_name,
+                                     const ObjectPath& object_path) {
+  AssertOnOriginThread();
+
+  // Check if we already have the requested object manager.
+  const ObjectManagerTable::key_type key(service_name + object_path.value());
+  ObjectManagerTable::iterator iter = object_manager_table_.find(key);
+  if (iter != object_manager_table_.end()) {
+    return iter->second.get();
+  }
+
+  scoped_refptr<ObjectManager> object_manager =
+      new ObjectManager(this, service_name, object_path);
+  object_manager_table_[key] = object_manager;
+
+  return object_manager.get();
+}
+
+bool Bus::RemoveObjectManager(const std::string& service_name,
+                              const ObjectPath& object_path,
+                              const base::Closure& callback) {
+  AssertOnOriginThread();
+  DCHECK(!callback.is_null());
+
+  const ObjectManagerTable::key_type key(service_name + object_path.value());
+  ObjectManagerTable::iterator iter = object_manager_table_.find(key);
+  if (iter == object_manager_table_.end())
+    return false;
+
+  // ObjectManager is present. Remove it now and CleanUp on the DBus thread.
+  scoped_refptr<ObjectManager> object_manager = iter->second;
+  object_manager_table_.erase(iter);
+
+  GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::RemoveObjectManagerInternal,
+                 this, object_manager, callback));
+
+  return true;
+}
+
+void Bus::RemoveObjectManagerInternal(
+      scoped_refptr<dbus::ObjectManager> object_manager,
+      const base::Closure& callback) {
+  AssertOnDBusThread();
+  DCHECK(object_manager.get());
+
+  object_manager->CleanUp();
+
+  // The ObjectManager has to be deleted on the origin thread since it was
+  // created there.
+  GetOriginTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::RemoveObjectManagerInternalHelper,
+                 this, object_manager, callback));
+}
+
+void Bus::RemoveObjectManagerInternalHelper(
+      scoped_refptr<dbus::ObjectManager> object_manager,
+      const base::Closure& callback) {
+  AssertOnOriginThread();
+  DCHECK(object_manager.get());
+
+  // Release the object manager and run the callback.
+  object_manager = NULL;
+  callback.Run();
+}
+
+void Bus::GetManagedObjects() {
+  for (ObjectManagerTable::iterator iter = object_manager_table_.begin();
+       iter != object_manager_table_.end(); ++iter) {
+    iter->second->GetManagedObjects();
+  }
+}
+
+bool Bus::Connect() {
+  // dbus_bus_get_private() and dbus_bus_get() are blocking calls.
+  AssertOnDBusThread();
+
+  // Check if it's already initialized.
+  if (connection_)
+    return true;
+
+  ScopedDBusError error;
+  if (bus_type_ == CUSTOM_ADDRESS) {
+    if (connection_type_ == PRIVATE) {
+      connection_ = dbus_connection_open_private(address_.c_str(), error.get());
+    } else {
+      connection_ = dbus_connection_open(address_.c_str(), error.get());
+    }
+  } else {
+    const DBusBusType dbus_bus_type = static_cast<DBusBusType>(bus_type_);
+    if (connection_type_ == PRIVATE) {
+      connection_ = dbus_bus_get_private(dbus_bus_type, error.get());
+    } else {
+      connection_ = dbus_bus_get(dbus_bus_type, error.get());
+    }
+  }
+  if (!connection_) {
+    LOG(ERROR) << "Failed to connect to the bus: "
+               << (error.is_set() ? error.message() : "");
+    return false;
+  }
+
+  if (bus_type_ == CUSTOM_ADDRESS) {
+    // We should call dbus_bus_register here, otherwise unique name can not be
+    // acquired. According to dbus specification, it is responsible to call
+    // org.freedesktop.DBus.Hello method at the beging of bus connection to
+    // acquire unique name. In the case of dbus_bus_get, dbus_bus_register is
+    // called internally.
+    if (!dbus_bus_register(connection_, error.get())) {
+      LOG(ERROR) << "Failed to register the bus component: "
+                 << (error.is_set() ? error.message() : "");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void Bus::ClosePrivateConnection() {
+  // dbus_connection_close is blocking call.
+  AssertOnDBusThread();
+  DCHECK_EQ(PRIVATE, connection_type_)
+      << "non-private connection should not be closed";
+  dbus_connection_close(connection_);
+}
+
+void Bus::ShutdownAndBlock() {
+  AssertOnDBusThread();
+
+  if (shutdown_completed_)
+    return;  // Already shutdowned, just return.
+
+  // Unregister the exported objects.
+  for (ExportedObjectTable::iterator iter = exported_object_table_.begin();
+       iter != exported_object_table_.end(); ++iter) {
+    iter->second->Unregister();
+  }
+
+  // Release all service names.
+  for (std::set<std::string>::iterator iter = owned_service_names_.begin();
+       iter != owned_service_names_.end();) {
+    // This is a bit tricky but we should increment the iter here as
+    // ReleaseOwnership() may remove |service_name| from the set.
+    const std::string& service_name = *iter++;
+    ReleaseOwnership(service_name);
+  }
+  if (!owned_service_names_.empty()) {
+    LOG(ERROR) << "Failed to release all service names. # of services left: "
+               << owned_service_names_.size();
+  }
+
+  // Detach from the remote objects.
+  for (ObjectProxyTable::iterator iter = object_proxy_table_.begin();
+       iter != object_proxy_table_.end(); ++iter) {
+    iter->second->Detach();
+  }
+
+  // Clean up the object managers.
+  for (ObjectManagerTable::iterator iter = object_manager_table_.begin();
+       iter != object_manager_table_.end(); ++iter) {
+    iter->second->CleanUp();
+  }
+
+  // Release object proxies and exported objects here. We should do this
+  // here rather than in the destructor to avoid memory leaks due to
+  // cyclic references.
+  object_proxy_table_.clear();
+  exported_object_table_.clear();
+
+  // Private connection should be closed.
+  if (connection_) {
+    // Remove Disconnected watcher.
+    ScopedDBusError error;
+
+    if (connection_type_ == PRIVATE)
+      ClosePrivateConnection();
+    // dbus_connection_close() won't unref.
+    dbus_connection_unref(connection_);
+  }
+
+  connection_ = NULL;
+  shutdown_completed_ = true;
+}
+
+void Bus::ShutdownOnDBusThreadAndBlock() {
+  AssertOnOriginThread();
+  DCHECK(dbus_task_runner_.get());
+
+  GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::ShutdownOnDBusThreadAndBlockInternal, this));
+
+  // http://crbug.com/125222
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+
+  // Wait until the shutdown is complete on the D-Bus thread.
+  // The shutdown should not hang, but set timeout just in case.
+  const int kTimeoutSecs = 3;
+  const base::TimeDelta timeout(base::TimeDelta::FromSeconds(kTimeoutSecs));
+  const bool signaled = on_shutdown_.TimedWait(timeout);
+  LOG_IF(ERROR, !signaled) << "Failed to shutdown the bus";
+}
+
+void Bus::RequestOwnership(const std::string& service_name,
+                           ServiceOwnershipOptions options,
+                           OnOwnershipCallback on_ownership_callback) {
+  AssertOnOriginThread();
+
+  GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::RequestOwnershipInternal,
+                 this, service_name, options, on_ownership_callback));
+}
+
+void Bus::RequestOwnershipInternal(const std::string& service_name,
+                                   ServiceOwnershipOptions options,
+                                   OnOwnershipCallback on_ownership_callback) {
+  AssertOnDBusThread();
+
+  bool success = Connect();
+  if (success)
+    success = RequestOwnershipAndBlock(service_name, options);
+
+  GetOriginTaskRunner()->PostTask(FROM_HERE,
+                                  base::Bind(on_ownership_callback,
+                                             service_name,
+                                             success));
+}
+
+bool Bus::RequestOwnershipAndBlock(const std::string& service_name,
+                                   ServiceOwnershipOptions options) {
+  DCHECK(connection_);
+  // dbus_bus_request_name() is a blocking call.
+  AssertOnDBusThread();
+
+  // Check if we already own the service name.
+  if (owned_service_names_.find(service_name) != owned_service_names_.end()) {
+    return true;
+  }
+
+  ScopedDBusError error;
+  const int result = dbus_bus_request_name(connection_,
+                                           service_name.c_str(),
+                                           options,
+                                           error.get());
+  if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+    LOG(ERROR) << "Failed to get the ownership of " << service_name << ": "
+               << (error.is_set() ? error.message() : "");
+    return false;
+  }
+  owned_service_names_.insert(service_name);
+  return true;
+}
+
+bool Bus::ReleaseOwnership(const std::string& service_name) {
+  DCHECK(connection_);
+  // dbus_bus_request_name() is a blocking call.
+  AssertOnDBusThread();
+
+  // Check if we already own the service name.
+  std::set<std::string>::iterator found =
+      owned_service_names_.find(service_name);
+  if (found == owned_service_names_.end()) {
+    LOG(ERROR) << service_name << " is not owned by the bus";
+    return false;
+  }
+
+  ScopedDBusError error;
+  const int result = dbus_bus_release_name(connection_, service_name.c_str(),
+                                           error.get());
+  if (result == DBUS_RELEASE_NAME_REPLY_RELEASED) {
+    owned_service_names_.erase(found);
+    return true;
+  } else {
+    LOG(ERROR) << "Failed to release the ownership of " << service_name << ": "
+               << (error.is_set() ? error.message() : "")
+               << ", result code: " << result;
+    return false;
+  }
+}
+
+bool Bus::SetUpAsyncOperations() {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  if (async_operations_set_up_)
+    return true;
+
+  // Process all the incoming data if any, so that OnDispatchStatus() will
+  // be called when the incoming data is ready.
+  ProcessAllIncomingDataIfAny();
+
+  bool success = dbus_connection_set_watch_functions(connection_,
+                                                     &Bus::OnAddWatchThunk,
+                                                     &Bus::OnRemoveWatchThunk,
+                                                     &Bus::OnToggleWatchThunk,
+                                                     this,
+                                                     NULL);
+  CHECK(success) << "Unable to allocate memory";
+
+  success = dbus_connection_set_timeout_functions(connection_,
+                                                  &Bus::OnAddTimeoutThunk,
+                                                  &Bus::OnRemoveTimeoutThunk,
+                                                  &Bus::OnToggleTimeoutThunk,
+                                                  this,
+                                                  NULL);
+  CHECK(success) << "Unable to allocate memory";
+
+  dbus_connection_set_dispatch_status_function(
+      connection_,
+      &Bus::OnDispatchStatusChangedThunk,
+      this,
+      NULL);
+
+  async_operations_set_up_ = true;
+
+  return true;
+}
+
+DBusMessage* Bus::SendWithReplyAndBlock(DBusMessage* request,
+                                        int timeout_ms,
+                                        DBusError* error) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  return dbus_connection_send_with_reply_and_block(
+      connection_, request, timeout_ms, error);
+}
+
+void Bus::SendWithReply(DBusMessage* request,
+                        DBusPendingCall** pending_call,
+                        int timeout_ms) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  const bool success = dbus_connection_send_with_reply(
+      connection_, request, pending_call, timeout_ms);
+  CHECK(success) << "Unable to allocate memory";
+}
+
+void Bus::Send(DBusMessage* request, uint32_t* serial) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  const bool success = dbus_connection_send(connection_, request, serial);
+  CHECK(success) << "Unable to allocate memory";
+}
+
+void Bus::AddFilterFunction(DBusHandleMessageFunction filter_function,
+                            void* user_data) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
+      std::make_pair(filter_function, user_data);
+  if (filter_functions_added_.find(filter_data_pair) !=
+      filter_functions_added_.end()) {
+    VLOG(1) << "Filter function already exists: " << filter_function
+            << " with associated data: " << user_data;
+    return;
+  }
+
+  const bool success = dbus_connection_add_filter(
+      connection_, filter_function, user_data, NULL);
+  CHECK(success) << "Unable to allocate memory";
+  filter_functions_added_.insert(filter_data_pair);
+}
+
+void Bus::RemoveFilterFunction(DBusHandleMessageFunction filter_function,
+                               void* user_data) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  std::pair<DBusHandleMessageFunction, void*> filter_data_pair =
+      std::make_pair(filter_function, user_data);
+  if (filter_functions_added_.find(filter_data_pair) ==
+      filter_functions_added_.end()) {
+    VLOG(1) << "Requested to remove an unknown filter function: "
+            << filter_function
+            << " with associated data: " << user_data;
+    return;
+  }
+
+  dbus_connection_remove_filter(connection_, filter_function, user_data);
+  filter_functions_added_.erase(filter_data_pair);
+}
+
+void Bus::AddMatch(const std::string& match_rule, DBusError* error) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  std::map<std::string, int>::iterator iter =
+      match_rules_added_.find(match_rule);
+  if (iter != match_rules_added_.end()) {
+    // The already existing rule's counter is incremented.
+    iter->second++;
+
+    VLOG(1) << "Match rule already exists: " << match_rule;
+    return;
+  }
+
+  dbus_bus_add_match(connection_, match_rule.c_str(), error);
+  match_rules_added_[match_rule] = 1;
+}
+
+bool Bus::RemoveMatch(const std::string& match_rule, DBusError* error) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  std::map<std::string, int>::iterator iter =
+      match_rules_added_.find(match_rule);
+  if (iter == match_rules_added_.end()) {
+    LOG(ERROR) << "Requested to remove an unknown match rule: " << match_rule;
+    return false;
+  }
+
+  // The rule's counter is decremented and the rule is deleted when reachs 0.
+  iter->second--;
+  if (iter->second == 0) {
+    dbus_bus_remove_match(connection_, match_rule.c_str(), error);
+    match_rules_added_.erase(match_rule);
+  }
+  return true;
+}
+
+bool Bus::TryRegisterObjectPath(const ObjectPath& object_path,
+                                const DBusObjectPathVTable* vtable,
+                                void* user_data,
+                                DBusError* error) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  if (registered_object_paths_.find(object_path) !=
+      registered_object_paths_.end()) {
+    LOG(ERROR) << "Object path already registered: " << object_path.value();
+    return false;
+  }
+
+  const bool success = dbus_connection_try_register_object_path(
+      connection_,
+      object_path.value().c_str(),
+      vtable,
+      user_data,
+      error);
+  if (success)
+    registered_object_paths_.insert(object_path);
+  return success;
+}
+
+void Bus::UnregisterObjectPath(const ObjectPath& object_path) {
+  DCHECK(connection_);
+  AssertOnDBusThread();
+
+  if (registered_object_paths_.find(object_path) ==
+      registered_object_paths_.end()) {
+    LOG(ERROR) << "Requested to unregister an unknown object path: "
+               << object_path.value();
+    return;
+  }
+
+  const bool success = dbus_connection_unregister_object_path(
+      connection_,
+      object_path.value().c_str());
+  CHECK(success) << "Unable to allocate memory";
+  registered_object_paths_.erase(object_path);
+}
+
+void Bus::ShutdownOnDBusThreadAndBlockInternal() {
+  AssertOnDBusThread();
+
+  ShutdownAndBlock();
+  on_shutdown_.Signal();
+}
+
+void Bus::ProcessAllIncomingDataIfAny() {
+  AssertOnDBusThread();
+
+  // As mentioned at the class comment in .h file, connection_ can be NULL.
+  if (!connection_)
+    return;
+
+  // It is safe and necessary to call dbus_connection_get_dispatch_status even
+  // if the connection is lost.
+  if (dbus_connection_get_dispatch_status(connection_) ==
+      DBUS_DISPATCH_DATA_REMAINS) {
+    while (dbus_connection_dispatch(connection_) ==
+           DBUS_DISPATCH_DATA_REMAINS) {
+    }
+  }
+}
+
+base::TaskRunner* Bus::GetDBusTaskRunner() {
+  if (dbus_task_runner_.get())
+    return dbus_task_runner_.get();
+  else
+    return GetOriginTaskRunner();
+}
+
+base::TaskRunner* Bus::GetOriginTaskRunner() {
+  DCHECK(origin_task_runner_.get());
+  return origin_task_runner_.get();
+}
+
+bool Bus::HasDBusThread() {
+  return dbus_task_runner_.get() != NULL;
+}
+
+void Bus::AssertOnOriginThread() {
+  DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId());
+}
+
+void Bus::AssertOnDBusThread() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (dbus_task_runner_.get()) {
+    DCHECK(dbus_task_runner_->RunsTasksOnCurrentThread());
+  } else {
+    AssertOnOriginThread();
+  }
+}
+
+std::string Bus::GetServiceOwnerAndBlock(const std::string& service_name,
+                                         GetServiceOwnerOption options) {
+  AssertOnDBusThread();
+
+  MethodCall get_name_owner_call("org.freedesktop.DBus", "GetNameOwner");
+  MessageWriter writer(&get_name_owner_call);
+  writer.AppendString(service_name);
+  VLOG(1) << "Method call: " << get_name_owner_call.ToString();
+
+  const ObjectPath obj_path("/org/freedesktop/DBus");
+  if (!get_name_owner_call.SetDestination("org.freedesktop.DBus") ||
+      !get_name_owner_call.SetPath(obj_path)) {
+    if (options == REPORT_ERRORS)
+      LOG(ERROR) << "Failed to get name owner.";
+    return "";
+  }
+
+  ScopedDBusError error;
+  DBusMessage* response_message =
+      SendWithReplyAndBlock(get_name_owner_call.raw_message(),
+                            ObjectProxy::TIMEOUT_USE_DEFAULT,
+                            error.get());
+  if (!response_message) {
+    if (options == REPORT_ERRORS) {
+      LOG(ERROR) << "Failed to get name owner. Got " << error.name() << ": "
+                 << error.message();
+    }
+    return "";
+  }
+
+  std::unique_ptr<Response> response(
+      Response::FromRawMessage(response_message));
+  MessageReader reader(response.get());
+
+  std::string service_owner;
+  if (!reader.PopString(&service_owner))
+    service_owner.clear();
+  return service_owner;
+}
+
+void Bus::GetServiceOwner(const std::string& service_name,
+                          const GetServiceOwnerCallback& callback) {
+  AssertOnOriginThread();
+
+  GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::GetServiceOwnerInternal, this, service_name, callback));
+}
+
+void Bus::GetServiceOwnerInternal(const std::string& service_name,
+                                  const GetServiceOwnerCallback& callback) {
+  AssertOnDBusThread();
+
+  std::string service_owner;
+  if (Connect())
+    service_owner = GetServiceOwnerAndBlock(service_name, SUPPRESS_ERRORS);
+  GetOriginTaskRunner()->PostTask(FROM_HERE,
+                                  base::Bind(callback, service_owner));
+}
+
+void Bus::ListenForServiceOwnerChange(
+    const std::string& service_name,
+    const GetServiceOwnerCallback& callback) {
+  AssertOnOriginThread();
+  DCHECK(!service_name.empty());
+  DCHECK(!callback.is_null());
+
+  GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::ListenForServiceOwnerChangeInternal,
+                 this, service_name, callback));
+}
+
+void Bus::ListenForServiceOwnerChangeInternal(
+    const std::string& service_name,
+    const GetServiceOwnerCallback& callback) {
+  AssertOnDBusThread();
+  DCHECK(!service_name.empty());
+  DCHECK(!callback.is_null());
+
+  if (!Connect() || !SetUpAsyncOperations())
+    return;
+
+  if (service_owner_changed_listener_map_.empty())
+    AddFilterFunction(Bus::OnServiceOwnerChangedFilter, this);
+
+  ServiceOwnerChangedListenerMap::iterator it =
+      service_owner_changed_listener_map_.find(service_name);
+  if (it == service_owner_changed_listener_map_.end()) {
+    // Add a match rule for the new service name.
+    const std::string name_owner_changed_match_rule =
+        base::StringPrintf(kServiceNameOwnerChangeMatchRule,
+                           service_name.c_str());
+    ScopedDBusError error;
+    AddMatch(name_owner_changed_match_rule, error.get());
+    if (error.is_set()) {
+      LOG(ERROR) << "Failed to add match rule for " << service_name
+                 << ". Got " << error.name() << ": " << error.message();
+      return;
+    }
+
+    service_owner_changed_listener_map_[service_name].push_back(callback);
+    return;
+  }
+
+  // Check if the callback has already been added.
+  std::vector<GetServiceOwnerCallback>& callbacks = it->second;
+  for (size_t i = 0; i < callbacks.size(); ++i) {
+    if (callbacks[i].Equals(callback))
+      return;
+  }
+  callbacks.push_back(callback);
+}
+
+void Bus::UnlistenForServiceOwnerChange(
+    const std::string& service_name,
+    const GetServiceOwnerCallback& callback) {
+  AssertOnOriginThread();
+  DCHECK(!service_name.empty());
+  DCHECK(!callback.is_null());
+
+  GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&Bus::UnlistenForServiceOwnerChangeInternal,
+                 this, service_name, callback));
+}
+
+void Bus::UnlistenForServiceOwnerChangeInternal(
+    const std::string& service_name,
+    const GetServiceOwnerCallback& callback) {
+  AssertOnDBusThread();
+  DCHECK(!service_name.empty());
+  DCHECK(!callback.is_null());
+
+  ServiceOwnerChangedListenerMap::iterator it =
+      service_owner_changed_listener_map_.find(service_name);
+  if (it == service_owner_changed_listener_map_.end())
+    return;
+
+  std::vector<GetServiceOwnerCallback>& callbacks = it->second;
+  for (size_t i = 0; i < callbacks.size(); ++i) {
+    if (callbacks[i].Equals(callback)) {
+      callbacks.erase(callbacks.begin() + i);
+      break;  // There can be only one.
+    }
+  }
+  if (!callbacks.empty())
+    return;
+
+  // Last callback for |service_name| has been removed, remove match rule.
+  const std::string name_owner_changed_match_rule =
+      base::StringPrintf(kServiceNameOwnerChangeMatchRule,
+                         service_name.c_str());
+  ScopedDBusError error;
+  RemoveMatch(name_owner_changed_match_rule, error.get());
+  // And remove |service_owner_changed_listener_map_| entry.
+  service_owner_changed_listener_map_.erase(it);
+
+  if (service_owner_changed_listener_map_.empty())
+    RemoveFilterFunction(Bus::OnServiceOwnerChangedFilter, this);
+}
+
+std::string Bus::GetConnectionName() {
+  if (!connection_)
+    return "";
+  return dbus_bus_get_unique_name(connection_);
+}
+
+dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch) {
+  AssertOnDBusThread();
+
+  // watch will be deleted when raw_watch is removed in OnRemoveWatch().
+  Watch* watch = new Watch(raw_watch);
+  if (watch->IsReadyToBeWatched()) {
+    watch->StartWatching();
+  }
+  ++num_pending_watches_;
+  return true;
+}
+
+void Bus::OnRemoveWatch(DBusWatch* raw_watch) {
+  AssertOnDBusThread();
+
+  Watch* watch = static_cast<Watch*>(dbus_watch_get_data(raw_watch));
+  delete watch;
+  --num_pending_watches_;
+}
+
+void Bus::OnToggleWatch(DBusWatch* raw_watch) {
+  AssertOnDBusThread();
+
+  Watch* watch = static_cast<Watch*>(dbus_watch_get_data(raw_watch));
+  if (watch->IsReadyToBeWatched()) {
+    watch->StartWatching();
+  } else {
+    // It's safe to call this if StartWatching() wasn't called, per
+    // message_pump_libevent.h.
+    watch->StopWatching();
+  }
+}
+
+dbus_bool_t Bus::OnAddTimeout(DBusTimeout* raw_timeout) {
+  AssertOnDBusThread();
+
+  // timeout will be deleted when raw_timeout is removed in
+  // OnRemoveTimeoutThunk().
+  Timeout* timeout = new Timeout(raw_timeout);
+  if (timeout->IsReadyToBeMonitored()) {
+    timeout->StartMonitoring(this);
+  }
+  ++num_pending_timeouts_;
+  return true;
+}
+
+void Bus::OnRemoveTimeout(DBusTimeout* raw_timeout) {
+  AssertOnDBusThread();
+
+  Timeout* timeout = static_cast<Timeout*>(dbus_timeout_get_data(raw_timeout));
+  timeout->Complete();
+  --num_pending_timeouts_;
+}
+
+void Bus::OnToggleTimeout(DBusTimeout* raw_timeout) {
+  AssertOnDBusThread();
+
+  Timeout* timeout = static_cast<Timeout*>(dbus_timeout_get_data(raw_timeout));
+  if (timeout->IsReadyToBeMonitored()) {
+    timeout->StartMonitoring(this);
+  } else {
+    timeout->StopMonitoring();
+  }
+}
+
+void Bus::OnDispatchStatusChanged(DBusConnection* connection,
+                                  DBusDispatchStatus /*status*/) {
+  DCHECK_EQ(connection, connection_);
+  AssertOnDBusThread();
+
+  // We cannot call ProcessAllIncomingDataIfAny() here, as calling
+  // dbus_connection_dispatch() inside DBusDispatchStatusFunction is
+  // prohibited by the D-Bus library. Hence, we post a task here instead.
+  // See comments for dbus_connection_set_dispatch_status_function().
+  GetDBusTaskRunner()->PostTask(FROM_HERE,
+                                base::Bind(&Bus::ProcessAllIncomingDataIfAny,
+                                           this));
+}
+
+void Bus::OnServiceOwnerChanged(DBusMessage* message) {
+  DCHECK(message);
+  AssertOnDBusThread();
+
+  // |message| will be unrefed on exit of the function. Increment the
+  // reference so we can use it in Signal::FromRawMessage() below.
+  dbus_message_ref(message);
+  std::unique_ptr<Signal> signal(Signal::FromRawMessage(message));
+
+  // Confirm the validity of the NameOwnerChanged signal.
+  if (signal->GetMember() != kNameOwnerChangedSignal ||
+      signal->GetInterface() != DBUS_INTERFACE_DBUS ||
+      signal->GetSender() != DBUS_SERVICE_DBUS) {
+    return;
+  }
+
+  MessageReader reader(signal.get());
+  std::string service_name;
+  std::string old_owner;
+  std::string new_owner;
+  if (!reader.PopString(&service_name) ||
+      !reader.PopString(&old_owner) ||
+      !reader.PopString(&new_owner)) {
+    return;
+  }
+
+  ServiceOwnerChangedListenerMap::const_iterator it =
+      service_owner_changed_listener_map_.find(service_name);
+  if (it == service_owner_changed_listener_map_.end())
+    return;
+
+  const std::vector<GetServiceOwnerCallback>& callbacks = it->second;
+  for (size_t i = 0; i < callbacks.size(); ++i) {
+    GetOriginTaskRunner()->PostTask(FROM_HERE,
+                                    base::Bind(callbacks[i], new_owner));
+  }
+}
+
+// static
+dbus_bool_t Bus::OnAddWatchThunk(DBusWatch* raw_watch, void* data) {
+  Bus* self = static_cast<Bus*>(data);
+  return self->OnAddWatch(raw_watch);
+}
+
+// static
+void Bus::OnRemoveWatchThunk(DBusWatch* raw_watch, void* data) {
+  Bus* self = static_cast<Bus*>(data);
+  self->OnRemoveWatch(raw_watch);
+}
+
+// static
+void Bus::OnToggleWatchThunk(DBusWatch* raw_watch, void* data) {
+  Bus* self = static_cast<Bus*>(data);
+  self->OnToggleWatch(raw_watch);
+}
+
+// static
+dbus_bool_t Bus::OnAddTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
+  Bus* self = static_cast<Bus*>(data);
+  return self->OnAddTimeout(raw_timeout);
+}
+
+// static
+void Bus::OnRemoveTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
+  Bus* self = static_cast<Bus*>(data);
+  self->OnRemoveTimeout(raw_timeout);
+}
+
+// static
+void Bus::OnToggleTimeoutThunk(DBusTimeout* raw_timeout, void* data) {
+  Bus* self = static_cast<Bus*>(data);
+  self->OnToggleTimeout(raw_timeout);
+}
+
+// static
+void Bus::OnDispatchStatusChangedThunk(DBusConnection* connection,
+                                       DBusDispatchStatus status,
+                                       void* data) {
+  Bus* self = static_cast<Bus*>(data);
+  self->OnDispatchStatusChanged(connection, status);
+}
+
+// static
+DBusHandlerResult Bus::OnServiceOwnerChangedFilter(
+    DBusConnection* /*connection*/,
+    DBusMessage* message,
+    void* data) {
+  if (dbus_message_is_signal(message,
+                             DBUS_INTERFACE_DBUS,
+                             kNameOwnerChangedSignal)) {
+    Bus* self = static_cast<Bus*>(data);
+    self->OnServiceOwnerChanged(message);
+  }
+  // Always return unhandled to let others, e.g. ObjectProxies, handle the same
+  // signal.
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/bus.h b/libchrome/dbus/bus.h
new file mode 100644
index 0000000..7d39159
--- /dev/null
+++ b/libchrome/dbus/bus.h
@@ -0,0 +1,766 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_BUS_H_
+#define DBUS_BUS_H_
+
+#include <dbus/dbus.h>
+#include <stdint.h>
+
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "dbus/dbus_export.h"
+#include "dbus/object_path.h"
+
+namespace base {
+class SequencedTaskRunner;
+class SingleThreadTaskRunner;
+class TaskRunner;
+}
+
+namespace tracked_objects {
+class Location;
+}
+
+namespace dbus {
+
+class ExportedObject;
+class ObjectManager;
+class ObjectProxy;
+
+// Bus is used to establish a connection with D-Bus, create object
+// proxies, and export objects.
+//
+// For asynchronous operations such as an asynchronous method call, the
+// bus object will use a task runner to monitor the underlying file
+// descriptor used for D-Bus communication. By default, the bus will use
+// the current thread's task runner. If |dbus_task_runner| option is
+// specified, the bus will use that task runner instead.
+//
+// THREADING
+//
+// In the D-Bus library, we use the two threads:
+//
+// - The origin thread: the thread that created the Bus object.
+// - The D-Bus thread: the thread servicing |dbus_task_runner|.
+//
+// The origin thread is usually Chrome's UI thread. The D-Bus thread is
+// usually a dedicated thread for the D-Bus library.
+//
+// BLOCKING CALLS
+//
+// Functions that issue blocking calls are marked "BLOCKING CALL" and
+// these functions should be called in the D-Bus thread (if
+// supplied). AssertOnDBusThread() is placed in these functions.
+//
+// Note that it's hard to tell if a libdbus function is actually blocking
+// or not (ex. dbus_bus_request_name() internally calls
+// dbus_connection_send_with_reply_and_block(), which is a blocking
+// call). To err on the safe side, we consider all libdbus functions that
+// deal with the connection to dbus-daemon to be blocking.
+//
+// SHUTDOWN
+//
+// The Bus object must be shut down manually by ShutdownAndBlock() and
+// friends. We require the manual shutdown to make the operation explicit
+// rather than doing it silently in the destructor.
+//
+// EXAMPLE USAGE:
+//
+// Synchronous method call:
+//
+//   dbus::Bus::Options options;
+//   // Set up the bus options here.
+//   ...
+//   dbus::Bus bus(options);
+//
+//   dbus::ObjectProxy* object_proxy =
+//       bus.GetObjectProxy(service_name, object_path);
+//
+//   dbus::MethodCall method_call(interface_name, method_name);
+//   std::unique_ptr<dbus::Response> response(
+//       object_proxy.CallMethodAndBlock(&method_call, timeout_ms));
+//   if (response.get() != NULL) {  // Success.
+//     ...
+//   }
+//
+// Asynchronous method call:
+//
+//   void OnResponse(dbus::Response* response) {
+//     // response is NULL if the method call failed.
+//     if (!response)
+//       return;
+//   }
+//
+//   ...
+//   object_proxy.CallMethod(&method_call, timeout_ms,
+//                           base::Bind(&OnResponse));
+//
+// Exporting a method:
+//
+//   void Echo(dbus::MethodCall* method_call,
+//             dbus::ExportedObject::ResponseSender response_sender) {
+//     // Do something with method_call.
+//     Response* response = Response::FromMethodCall(method_call);
+//     // Build response here.
+//     // Can send an immediate response here to implement a synchronous service
+//     // or store the response_sender and send a response later to implement an
+//     // asynchronous service.
+//     response_sender.Run(response);
+//   }
+//
+//   void OnExported(const std::string& interface_name,
+//                   const ObjectPath& object_path,
+//                   bool success) {
+//     // success is true if the method was exported successfully.
+//   }
+//
+//   ...
+//   dbus::ExportedObject* exported_object =
+//       bus.GetExportedObject(service_name, object_path);
+//   exported_object.ExportMethod(interface_name, method_name,
+//                                base::Bind(&Echo),
+//                                base::Bind(&OnExported));
+//
+// WHY IS THIS A REF COUNTED OBJECT?
+//
+// Bus is a ref counted object, to ensure that |this| of the object is
+// alive when callbacks referencing |this| are called. However, after the
+// bus is shut down, |connection_| can be NULL. Hence, callbacks should
+// not rely on that |connection_| is alive.
+class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
+ public:
+  // Specifies the bus type. SESSION is used to communicate with per-user
+  // services like GNOME applications. SYSTEM is used to communicate with
+  // system-wide services like NetworkManager. CUSTOM_ADDRESS is used to
+  // communicate with an user specified address.
+  enum BusType {
+    SESSION = DBUS_BUS_SESSION,
+    SYSTEM = DBUS_BUS_SYSTEM,
+    CUSTOM_ADDRESS,
+  };
+
+  // Specifies the connection type. PRIVATE should usually be used unless
+  // you are sure that SHARED is safe for you, which is unlikely the case
+  // in Chrome.
+  //
+  // PRIVATE gives you a private connection, that won't be shared with
+  // other Bus objects.
+  //
+  // SHARED gives you a connection shared among other Bus objects, which
+  // is unsafe if the connection is shared with multiple threads.
+  enum ConnectionType {
+    PRIVATE,
+    SHARED,
+  };
+
+  // Specifies whether the GetServiceOwnerAndBlock call should report or
+  // suppress errors.
+  enum GetServiceOwnerOption {
+    REPORT_ERRORS,
+    SUPPRESS_ERRORS,
+  };
+
+  // Specifies service ownership options.
+  //
+  // REQUIRE_PRIMARY indicates that you require primary ownership of the
+  // service name.
+  //
+  // ALLOW_REPLACEMENT indicates that you'll allow another connection to
+  // steal ownership of this service name from you.
+  //
+  // REQUIRE_PRIMARY_ALLOW_REPLACEMENT does the obvious.
+  enum ServiceOwnershipOptions {
+    REQUIRE_PRIMARY = (DBUS_NAME_FLAG_DO_NOT_QUEUE |
+                       DBUS_NAME_FLAG_REPLACE_EXISTING),
+    REQUIRE_PRIMARY_ALLOW_REPLACEMENT = (REQUIRE_PRIMARY |
+                                         DBUS_NAME_FLAG_ALLOW_REPLACEMENT),
+  };
+
+  // Options used to create a Bus object.
+  struct CHROME_DBUS_EXPORT Options {
+    Options();
+    ~Options();
+
+    BusType bus_type;  // SESSION by default.
+    ConnectionType connection_type;  // PRIVATE by default.
+    // If dbus_task_runner is set, the bus object will use that
+    // task runner to process asynchronous operations.
+    //
+    // The thread servicing the task runner should meet the following
+    // requirements:
+    // 1) Already running.
+    // 2) Has a MessageLoopForIO.
+    scoped_refptr<base::SequencedTaskRunner> dbus_task_runner;
+
+    // Specifies the server addresses to be connected. If you want to
+    // communicate with non dbus-daemon such as ibus-daemon, set |bus_type| to
+    // CUSTOM_ADDRESS, and |address| to the D-Bus server address you want to
+    // connect to. The format of this address value is the dbus address style
+    // which is described in
+    // http://dbus.freedesktop.org/doc/dbus-specification.html#addresses
+    //
+    // EXAMPLE USAGE:
+    //   dbus::Bus::Options options;
+    //   options.bus_type = CUSTOM_ADDRESS;
+    //   options.address.assign("unix:path=/tmp/dbus-XXXXXXX");
+    //   // Set up other options
+    //   dbus::Bus bus(options);
+    //
+    //   // Do something.
+    //
+    std::string address;
+  };
+
+  // Creates a Bus object. The actual connection will be established when
+  // Connect() is called.
+  explicit Bus(const Options& options);
+
+  // Called when an ownership request is complete.
+  // Parameters:
+  // - the requested service name.
+  // - whether ownership has been obtained or not.
+  typedef base::Callback<void (const std::string&, bool)> OnOwnershipCallback;
+
+  // Called when GetServiceOwner() completes.
+  // |service_owner| is the return value from GetServiceOwnerAndBlock().
+  typedef base::Callback<void (const std::string& service_owner)>
+      GetServiceOwnerCallback;
+
+  // TODO(satorux): Remove the service name parameter as the caller of
+  // RequestOwnership() knows the service name.
+
+  // Gets the object proxy for the given service name and the object path.
+  // The caller must not delete the returned object.
+  //
+  // Returns an existing object proxy if the bus object already owns the
+  // object proxy for the given service name and the object path.
+  // Never returns NULL.
+  //
+  // The bus will own all object proxies created by the bus, to ensure
+  // that the object proxies are detached from remote objects at the
+  // shutdown time of the bus.
+  //
+  // The object proxy is used to call methods of remote objects, and
+  // receive signals from them.
+  //
+  // |service_name| looks like "org.freedesktop.NetworkManager", and
+  // |object_path| looks like "/org/freedesktop/NetworkManager/Devices/0".
+  //
+  // Must be called in the origin thread.
+  virtual ObjectProxy* GetObjectProxy(const std::string& service_name,
+                                      const ObjectPath& object_path);
+
+  // Same as above, but also takes a bitfield of ObjectProxy::Options.
+  // See object_proxy.h for available options.
+  virtual ObjectProxy* GetObjectProxyWithOptions(
+      const std::string& service_name,
+      const ObjectPath& object_path,
+      int options);
+
+  // Removes the previously created object proxy for the given service
+  // name and the object path and releases its memory.
+  //
+  // If and object proxy for the given service name and object was
+  // created with GetObjectProxy, this function removes it from the
+  // bus object and detaches the ObjectProxy, invalidating any pointer
+  // previously acquired for it with GetObjectProxy. A subsequent call
+  // to GetObjectProxy will return a new object.
+  //
+  // All the object proxies are detached from remote objects at the
+  // shutdown time of the bus, but they can be detached early to reduce
+  // memory footprint and used match rules for the bus connection.
+  //
+  // |service_name| looks like "org.freedesktop.NetworkManager", and
+  // |object_path| looks like "/org/freedesktop/NetworkManager/Devices/0".
+  // |callback| is called when the object proxy is successfully removed and
+  // detached.
+  //
+  // The function returns true when there is an object proxy matching the
+  // |service_name| and |object_path| to remove, and calls |callback| when it
+  // is removed. Otherwise, it returns false and the |callback| function is
+  // never called. The |callback| argument must not be null.
+  //
+  // Must be called in the origin thread.
+  virtual bool RemoveObjectProxy(const std::string& service_name,
+                                 const ObjectPath& object_path,
+                                 const base::Closure& callback);
+
+  // Same as above, but also takes a bitfield of ObjectProxy::Options.
+  // See object_proxy.h for available options.
+  virtual bool RemoveObjectProxyWithOptions(
+      const std::string& service_name,
+      const ObjectPath& object_path,
+      int options,
+      const base::Closure& callback);
+
+  // Gets the exported object for the given object path.
+  // The caller must not delete the returned object.
+  //
+  // Returns an existing exported object if the bus object already owns
+  // the exported object for the given object path. Never returns NULL.
+  //
+  // The bus will own all exported objects created by the bus, to ensure
+  // that the exported objects are unregistered at the shutdown time of
+  // the bus.
+  //
+  // The exported object is used to export methods of local objects, and
+  // send signal from them.
+  //
+  // Must be called in the origin thread.
+  virtual ExportedObject* GetExportedObject(const ObjectPath& object_path);
+
+  // Unregisters the exported object for the given object path |object_path|.
+  //
+  // Getting an exported object for the same object path after this call
+  // will return a new object, method calls on any remaining copies of the
+  // previous object will not be called.
+  //
+  // Must be called in the origin thread.
+  virtual void UnregisterExportedObject(const ObjectPath& object_path);
+
+
+  // Gets an object manager for the given remote object path |object_path|
+  // exported by the service |service_name|.
+  //
+  // Returns an existing object manager if the bus object already owns a
+  // matching object manager, never returns NULL.
+  //
+  // The caller must not delete the returned object, the bus retains ownership
+  // of all object managers.
+  //
+  // Must be called in the origin thread.
+  virtual ObjectManager* GetObjectManager(const std::string& service_name,
+                                          const ObjectPath& object_path);
+
+  // Unregisters the object manager for the given remote object path
+  // |object_path| exported by the srevice |service_name|.
+  //
+  // Getting an object manager for the same remote object after this call
+  // will return a new object, method calls on any remaining copies of the
+  // previous object are not permitted.
+  //
+  // This method will asynchronously clean up any match rules that have been
+  // added for the object manager and invoke |callback| when the operation is
+  // complete. If this method returns false, then |callback| is never called.
+  // The |callback| argument must not be null.
+  //
+  // Must be called in the origin thread.
+  virtual bool RemoveObjectManager(const std::string& service_name,
+                                   const ObjectPath& object_path,
+                                   const base::Closure& callback);
+
+  // Instructs all registered object managers to retrieve their set of managed
+  // objects from their respective remote objects. There is no need to call this
+  // manually, this is called automatically by the D-Bus thread manager once
+  // implementation classes are registered.
+  virtual void GetManagedObjects();
+
+  // Shuts down the bus and blocks until it's done. More specifically, this
+  // function does the following:
+  //
+  // - Unregisters the object paths
+  // - Releases the service names
+  // - Closes the connection to dbus-daemon.
+  //
+  // This function can be called multiple times and it is no-op for the 2nd time
+  // calling.
+  //
+  // BLOCKING CALL.
+  virtual void ShutdownAndBlock();
+
+  // Similar to ShutdownAndBlock(), but this function is used to
+  // synchronously shut down the bus that uses the D-Bus thread. This
+  // function is intended to be used at the very end of the browser
+  // shutdown, where it makes more sense to shut down the bus
+  // synchronously, than trying to make it asynchronous.
+  //
+  // BLOCKING CALL, but must be called in the origin thread.
+  virtual void ShutdownOnDBusThreadAndBlock();
+
+  // Returns true if the shutdown has been completed.
+  bool shutdown_completed() { return shutdown_completed_; }
+
+  //
+  // The public functions below are not intended to be used in client
+  // code. These are used to implement ObjectProxy and ExportedObject.
+  //
+
+  // Connects the bus to the dbus-daemon.
+  // Returns true on success, or the bus is already connected.
+  //
+  // BLOCKING CALL.
+  virtual bool Connect();
+
+  // Disconnects the bus from the dbus-daemon.
+  // Safe to call multiple times and no operation after the first call.
+  // Do not call for shared connection it will be released by libdbus.
+  //
+  // BLOCKING CALL.
+  virtual void ClosePrivateConnection();
+
+  // Requests the ownership of the service name given by |service_name|.
+  // See also RequestOwnershipAndBlock().
+  //
+  // |on_ownership_callback| is called when the service name is obtained
+  // or failed to be obtained, in the origin thread.
+  //
+  // Must be called in the origin thread.
+  virtual void RequestOwnership(const std::string& service_name,
+                                ServiceOwnershipOptions options,
+                                OnOwnershipCallback on_ownership_callback);
+
+  // Requests the ownership of the given service name.
+  // Returns true on success, or the the service name is already obtained.
+  //
+  // Note that it's important to expose methods before requesting a service
+  // name with this method.  See also ExportedObject::ExportMethodAndBlock()
+  // for details.
+  //
+  // BLOCKING CALL.
+  virtual bool RequestOwnershipAndBlock(const std::string& service_name,
+                                        ServiceOwnershipOptions options);
+
+  // Releases the ownership of the given service name.
+  // Returns true on success.
+  //
+  // BLOCKING CALL.
+  virtual bool ReleaseOwnership(const std::string& service_name);
+
+  // Sets up async operations.
+  // Returns true on success, or it's already set up.
+  // This function needs to be called before starting async operations.
+  //
+  // BLOCKING CALL.
+  virtual bool SetUpAsyncOperations();
+
+  // Sends a message to the bus and blocks until the response is
+  // received. Used to implement synchronous method calls.
+  //
+  // BLOCKING CALL.
+  virtual DBusMessage* SendWithReplyAndBlock(DBusMessage* request,
+                                             int timeout_ms,
+                                             DBusError* error);
+
+  // Requests to send a message to the bus. The reply is handled with
+  // |pending_call| at a later time.
+  //
+  // BLOCKING CALL.
+  virtual void SendWithReply(DBusMessage* request,
+                             DBusPendingCall** pending_call,
+                             int timeout_ms);
+
+  // Requests to send a message to the bus. The message serial number will
+  // be stored in |serial|.
+  //
+  // BLOCKING CALL.
+  virtual void Send(DBusMessage* request, uint32_t* serial);
+
+  // Adds the message filter function. |filter_function| will be called
+  // when incoming messages are received.
+  //
+  // When a new incoming message arrives, filter functions are called in
+  // the order that they were added until the the incoming message is
+  // handled by a filter function.
+  //
+  // The same filter function associated with the same user data cannot be
+  // added more than once.
+  //
+  // BLOCKING CALL.
+  virtual void AddFilterFunction(DBusHandleMessageFunction filter_function,
+                                 void* user_data);
+
+  // Removes the message filter previously added by AddFilterFunction().
+  //
+  // BLOCKING CALL.
+  virtual void RemoveFilterFunction(DBusHandleMessageFunction filter_function,
+                                    void* user_data);
+
+  // Adds the match rule. Messages that match the rule will be processed
+  // by the filter functions added by AddFilterFunction().
+  //
+  // You cannot specify which filter function to use for a match rule.
+  // Instead, you should check if an incoming message is what you are
+  // interested in, in the filter functions.
+  //
+  // The same match rule can be added more than once and should be removed
+  // as many times as it was added.
+  //
+  // The match rule looks like:
+  // "type='signal', interface='org.chromium.SomeInterface'".
+  //
+  // See "Message Bus Message Routing" section in the D-Bus specification
+  // for details about match rules:
+  // http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing
+  //
+  // BLOCKING CALL.
+  virtual void AddMatch(const std::string& match_rule, DBusError* error);
+
+  // Removes the match rule previously added by AddMatch().
+  // Returns false if the requested match rule is unknown or has already been
+  // removed. Otherwise, returns true and sets |error| accordingly.
+  //
+  // BLOCKING CALL.
+  virtual bool RemoveMatch(const std::string& match_rule, DBusError* error);
+
+  // Tries to register the object path. Returns true on success.
+  // Returns false if the object path is already registered.
+  //
+  // |message_function| in |vtable| will be called every time when a new
+  // |message sent to the object path arrives.
+  //
+  // The same object path must not be added more than once.
+  //
+  // See also documentation of |dbus_connection_try_register_object_path| at
+  // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
+  //
+  // BLOCKING CALL.
+  virtual bool TryRegisterObjectPath(const ObjectPath& object_path,
+                                     const DBusObjectPathVTable* vtable,
+                                     void* user_data,
+                                     DBusError* error);
+
+  // Unregister the object path.
+  //
+  // BLOCKING CALL.
+  virtual void UnregisterObjectPath(const ObjectPath& object_path);
+
+  // Returns the task runner of the D-Bus thread.
+  virtual base::TaskRunner* GetDBusTaskRunner();
+
+  // Returns the task runner of the thread that created the bus.
+  virtual base::TaskRunner* GetOriginTaskRunner();
+
+  // Returns true if the bus has the D-Bus thread.
+  virtual bool HasDBusThread();
+
+  // Check whether the current thread is on the origin thread (the thread
+  // that created the bus). If not, DCHECK will fail.
+  virtual void AssertOnOriginThread();
+
+  // Check whether the current thread is on the D-Bus thread. If not,
+  // DCHECK will fail. If the D-Bus thread is not supplied, it calls
+  // AssertOnOriginThread().
+  virtual void AssertOnDBusThread();
+
+  // Gets the owner for |service_name| via org.freedesktop.DBus.GetNameOwner.
+  // Returns the owner name, if any, or an empty string on failure.
+  // |options| specifies where to printing error messages or not.
+  //
+  // BLOCKING CALL.
+  virtual std::string GetServiceOwnerAndBlock(const std::string& service_name,
+                                              GetServiceOwnerOption options);
+
+  // A non-blocking version of GetServiceOwnerAndBlock().
+  // Must be called in the origin thread.
+  virtual void GetServiceOwner(const std::string& service_name,
+                               const GetServiceOwnerCallback& callback);
+
+  // Whenever the owner for |service_name| changes, run |callback| with the
+  // name of the new owner. If the owner goes away, then |callback| receives
+  // an empty string.
+  //
+  // Any unique (service_name, callback) can be used. Duplicate are ignored.
+  // |service_name| must not be empty and |callback| must not be null.
+  //
+  // Must be called in the origin thread.
+  virtual void ListenForServiceOwnerChange(
+      const std::string& service_name,
+      const GetServiceOwnerCallback& callback);
+
+  // Stop listening for |service_name| owner changes for |callback|.
+  // Any unique (service_name, callback) can be used. Non-registered callbacks
+  // for a given service name are ignored.
+  // |service_name| must not be empty and |callback| must not be null.
+  //
+  // Must be called in the origin thread.
+  virtual void UnlistenForServiceOwnerChange(
+      const std::string& service_name,
+      const GetServiceOwnerCallback& callback);
+
+  // Return the unique name of the bus connnection if it is connected to
+  // D-BUS. Otherwise, return an empty string.
+  std::string GetConnectionName();
+
+  // Returns true if the bus is connected to D-Bus.
+  bool is_connected() { return connection_ != NULL; }
+
+ protected:
+  // This is protected, so we can define sub classes.
+  virtual ~Bus();
+
+ private:
+  friend class base::RefCountedThreadSafe<Bus>;
+
+  // Helper function used for RemoveObjectProxy().
+  void RemoveObjectProxyInternal(scoped_refptr<dbus::ObjectProxy> object_proxy,
+                                 const base::Closure& callback);
+
+  // Helper functions used for RemoveObjectManager().
+  void RemoveObjectManagerInternal(
+      scoped_refptr<dbus::ObjectManager> object_manager,
+      const base::Closure& callback);
+  void RemoveObjectManagerInternalHelper(
+      scoped_refptr<dbus::ObjectManager> object_manager,
+      const base::Closure& callback);
+
+  // Helper function used for UnregisterExportedObject().
+  void UnregisterExportedObjectInternal(
+      scoped_refptr<dbus::ExportedObject> exported_object);
+
+  // Helper function used for ShutdownOnDBusThreadAndBlock().
+  void ShutdownOnDBusThreadAndBlockInternal();
+
+  // Helper function used for RequestOwnership().
+  void RequestOwnershipInternal(const std::string& service_name,
+                                ServiceOwnershipOptions options,
+                                OnOwnershipCallback on_ownership_callback);
+
+  // Helper function used for GetServiceOwner().
+  void GetServiceOwnerInternal(const std::string& service_name,
+                               const GetServiceOwnerCallback& callback);
+
+  // Helper function used for ListenForServiceOwnerChange().
+  void ListenForServiceOwnerChangeInternal(
+      const std::string& service_name,
+      const GetServiceOwnerCallback& callback);
+
+  // Helper function used for UnListenForServiceOwnerChange().
+  void UnlistenForServiceOwnerChangeInternal(
+      const std::string& service_name,
+      const GetServiceOwnerCallback& callback);
+
+  // Processes the all incoming data to the connection, if any.
+  //
+  // BLOCKING CALL.
+  void ProcessAllIncomingDataIfAny();
+
+  // Called when a watch object is added. Used to start monitoring the
+  // file descriptor used for D-Bus communication.
+  dbus_bool_t OnAddWatch(DBusWatch* raw_watch);
+
+  // Called when a watch object is removed.
+  void OnRemoveWatch(DBusWatch* raw_watch);
+
+  // Called when the "enabled" status of |raw_watch| is toggled.
+  void OnToggleWatch(DBusWatch* raw_watch);
+
+  // Called when a timeout object is added. Used to start monitoring
+  // timeout for method calls.
+  dbus_bool_t OnAddTimeout(DBusTimeout* raw_timeout);
+
+  // Called when a timeout object is removed.
+  void OnRemoveTimeout(DBusTimeout* raw_timeout);
+
+  // Called when the "enabled" status of |raw_timeout| is toggled.
+  void OnToggleTimeout(DBusTimeout* raw_timeout);
+
+  // Called when the dispatch status (i.e. if any incoming data is
+  // available) is changed.
+  void OnDispatchStatusChanged(DBusConnection* connection,
+                               DBusDispatchStatus status);
+
+  // Called when a service owner change occurs.
+  void OnServiceOwnerChanged(DBusMessage* message);
+
+  // Callback helper functions. Redirects to the corresponding member function.
+  static dbus_bool_t OnAddWatchThunk(DBusWatch* raw_watch, void* data);
+  static void OnRemoveWatchThunk(DBusWatch* raw_watch, void* data);
+  static void OnToggleWatchThunk(DBusWatch* raw_watch, void* data);
+  static dbus_bool_t OnAddTimeoutThunk(DBusTimeout* raw_timeout, void* data);
+  static void OnRemoveTimeoutThunk(DBusTimeout* raw_timeout, void* data);
+  static void OnToggleTimeoutThunk(DBusTimeout* raw_timeout, void* data);
+  static void OnDispatchStatusChangedThunk(DBusConnection* connection,
+                                           DBusDispatchStatus status,
+                                           void* data);
+
+  // Calls OnConnectionDisconnected if the Disconnected signal is received.
+  static DBusHandlerResult OnConnectionDisconnectedFilter(
+      DBusConnection* connection,
+      DBusMessage* message,
+      void* user_data);
+
+  // Calls OnServiceOwnerChanged for a NameOwnerChanged signal.
+  static DBusHandlerResult OnServiceOwnerChangedFilter(
+      DBusConnection* connection,
+      DBusMessage* message,
+      void* user_data);
+
+  const BusType bus_type_;
+  const ConnectionType connection_type_;
+  scoped_refptr<base::SequencedTaskRunner> dbus_task_runner_;
+  base::WaitableEvent on_shutdown_;
+  DBusConnection* connection_;
+
+  scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
+  base::PlatformThreadId origin_thread_id_;
+
+  std::set<std::string> owned_service_names_;
+  // The following sets are used to check if rules/object_paths/filters
+  // are properly cleaned up before destruction of the bus object.
+  // Since it's not an error to add the same match rule twice, the repeated
+  // match rules are counted in a map.
+  std::map<std::string, int> match_rules_added_;
+  std::set<ObjectPath> registered_object_paths_;
+  std::set<std::pair<DBusHandleMessageFunction, void*> >
+      filter_functions_added_;
+
+  // ObjectProxyTable is used to hold the object proxies created by the
+  // bus object. Key is a pair; the first part is a concatenated string of
+  // service name + object path, like
+  // "org.chromium.TestService/org/chromium/TestObject".
+  // The second part is the ObjectProxy::Options for the proxy.
+  typedef std::map<std::pair<std::string, int>,
+                   scoped_refptr<dbus::ObjectProxy> > ObjectProxyTable;
+  ObjectProxyTable object_proxy_table_;
+
+  // ExportedObjectTable is used to hold the exported objects created by
+  // the bus object. Key is a concatenated string of service name +
+  // object path, like "org.chromium.TestService/org/chromium/TestObject".
+  typedef std::map<const dbus::ObjectPath,
+                   scoped_refptr<dbus::ExportedObject> > ExportedObjectTable;
+  ExportedObjectTable exported_object_table_;
+
+  // ObjectManagerTable is used to hold the object managers created by the
+  // bus object. Key is a concatenated string of service name + object path,
+  // like "org.chromium.TestService/org/chromium/TestObject".
+  typedef std::map<std::string,
+                   scoped_refptr<dbus::ObjectManager> > ObjectManagerTable;
+  ObjectManagerTable object_manager_table_;
+
+  // A map of NameOwnerChanged signals to listen for and the callbacks to run
+  // on the origin thread when the owner changes.
+  // Only accessed on the DBus thread.
+  // Key: Service name
+  // Value: Vector of callbacks. Unique and expected to be small. Not using
+  //        std::set here because base::Callbacks don't have a '<' operator.
+  typedef std::map<std::string, std::vector<GetServiceOwnerCallback> >
+      ServiceOwnerChangedListenerMap;
+  ServiceOwnerChangedListenerMap service_owner_changed_listener_map_;
+
+  bool async_operations_set_up_;
+  bool shutdown_completed_;
+
+  // Counters to make sure that OnAddWatch()/OnRemoveWatch() and
+  // OnAddTimeout()/OnRemoveTimeou() are balanced.
+  int num_pending_watches_;
+  int num_pending_timeouts_;
+
+  std::string address_;
+
+  DISALLOW_COPY_AND_ASSIGN(Bus);
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_BUS_H_
diff --git a/libchrome/dbus/dbus.gyp b/libchrome/dbus/dbus.gyp
new file mode 100644
index 0000000..264383e
--- /dev/null
+++ b/libchrome/dbus/dbus.gyp
@@ -0,0 +1,141 @@
+# Copyright (c) 2012 The Chromium 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,
+  },
+  'targets': [
+    {
+      'target_name': 'dbus',
+      'type': '<(component)',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../build/linux/system.gyp:dbus',
+        '../third_party/protobuf/protobuf.gyp:protobuf_lite',
+      ],
+      'export_dependent_settings': [
+        '../base/base.gyp:base',
+      ],
+      'defines': [
+        'DBUS_IMPLEMENTATION',
+      ],
+      'sources': [
+        'bus.cc',
+        'bus.h',
+        'dbus_export.h',
+        'dbus_statistics.cc',
+        'dbus_statistics.h',
+        'exported_object.cc',
+        'exported_object.h',
+        'file_descriptor.cc',
+        'file_descriptor.h',
+        'message.cc',
+        'message.h',
+        'object_manager.cc',
+        'object_manager.h',
+        'object_path.cc',
+        'object_path.h',
+        'object_proxy.cc',
+        'object_proxy.h',
+        'property.cc',
+        'property.h',
+        'scoped_dbus_error.cc',
+        'scoped_dbus_error.h',
+        'string_util.cc',
+        'string_util.h',
+        'util.cc',
+        'util.h',
+        'values_util.cc',
+        'values_util.h',
+      ],
+    },
+    {
+      # Protobuf compiler / generator test protocol buffer
+      'target_name': 'dbus_test_proto',
+      'type': 'static_library',
+      'sources': [ 'test_proto.proto' ],
+      'variables': {
+        'proto_out_dir': 'dbus',
+      },
+      'includes': [ '../build/protoc.gypi' ],
+    },
+    {
+      # This target contains mocks that can be used to write unit tests
+      # without issuing actual D-Bus calls.
+      'target_name': 'dbus_test_support',
+      'type': 'static_library',
+      'dependencies': [
+        '../build/linux/system.gyp:dbus',
+        '../testing/gmock.gyp:gmock',
+        'dbus',
+      ],
+      'sources': [
+        'mock_bus.cc',
+        'mock_bus.h',
+        'mock_exported_object.cc',
+        'mock_exported_object.h',
+        'mock_object_manager.cc',
+        'mock_object_manager.h',
+        'mock_object_proxy.cc',
+        'mock_object_proxy.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
+      'target_name': 'dbus_unittests',
+      'type': 'executable',
+      'dependencies': [
+        '../base/base.gyp:run_all_unittests',
+        '../base/base.gyp:test_support_base',
+        '../build/linux/system.gyp:dbus',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        'dbus',
+        'dbus_test_proto',
+        'dbus_test_support',
+      ],
+      'sources': [
+        'bus_unittest.cc',
+        'dbus_statistics_unittest.cc',
+        'end_to_end_async_unittest.cc',
+        'end_to_end_sync_unittest.cc',
+        'message_unittest.cc',
+        'mock_unittest.cc',
+        'object_manager_unittest.cc',
+        'object_proxy_unittest.cc',
+        'property_unittest.cc',
+        'signal_sender_verification_unittest.cc',
+        'string_util_unittest.cc',
+        'test_service.cc',
+        'test_service.h',
+        'util_unittest.cc',
+        'values_util_unittest.cc',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
+      'target_name': 'dbus_test_server',
+      'type': 'executable',
+      'dependencies': [
+        '../base/base.gyp:test_support_base',
+        '../base/base.gyp:base',
+        '../build/linux/system.gyp:dbus',
+        'dbus',
+      ],
+      'sources': [
+        'test_server.cc',
+        'test_service.cc',
+        'test_service.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+  ],
+}
diff --git a/libchrome/dbus/dbus_export.h b/libchrome/dbus/dbus_export.h
new file mode 100644
index 0000000..7c96d17
--- /dev/null
+++ b/libchrome/dbus/dbus_export.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 DBUS_DBUS_EXPORT_H_
+#define DBUS_DBUS_EXPORT_H_
+
+// Defines CHROME_DBUS_EXPORT so that functionality implemented by the dbus
+// library can be exported to consumers.
+// NOTE: We haven't used DBUS_EXPORT because it would conflict with the version
+// from /usr/include/dbus-1.0/dbus/dbus-macros.h.
+
+#if defined(WIN32)
+#error dbus support is not currently expected to work on windows
+#endif  // defined(WIN32)
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(DBUS_IMPLEMENTATION)
+#define CHROME_DBUS_EXPORT __attribute__((visibility("default")))
+#else
+#define CHROME_DBUS_EXPORT
+#endif
+
+#else  // !defined(COMPONENT_BUILD)
+
+#define CHROME_DBUS_EXPORT
+
+#endif  // defined(COMPONENT_BUILD)
+
+#endif  // DBUS_DBUS_EXPORT_H_
diff --git a/libchrome/dbus/dbus_statistics.cc b/libchrome/dbus/dbus_statistics.cc
new file mode 100644
index 0000000..e1e0973
--- /dev/null
+++ b/libchrome/dbus/dbus_statistics.cc
@@ -0,0 +1,284 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/dbus_statistics.h"
+
+#include <memory>
+#include <set>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+namespace dbus {
+
+namespace {
+
+// Used to store dbus statistics sorted alphabetically by service, interface,
+// then method (using std::string <).
+struct Stat {
+  Stat(const std::string& service,
+       const std::string& interface,
+       const std::string& method)
+      : service(service),
+        interface(interface),
+        method(method),
+        sent_method_calls(0),
+        received_signals(0),
+        sent_blocking_method_calls(0) {
+  }
+  std::string service;
+  std::string interface;
+  std::string method;
+  int sent_method_calls;
+  int received_signals;
+  int sent_blocking_method_calls;
+
+  bool Compare(const Stat& other) const {
+    if (service != other.service)
+      return service < other.service;
+    if (interface != other.interface)
+      return interface < other.interface;
+    return method < other.method;
+  }
+
+  struct PtrCompare {
+    bool operator()(Stat* lhs, Stat* rhs) const {
+      DCHECK(lhs && rhs);
+      return lhs->Compare(*rhs);
+    }
+  };
+};
+
+typedef std::set<Stat*, Stat::PtrCompare> StatSet;
+
+//------------------------------------------------------------------------------
+// DBusStatistics
+
+// Simple class for gathering DBus usage statistics.
+class DBusStatistics {
+ public:
+  DBusStatistics()
+      : start_time_(base::Time::Now()),
+        origin_thread_id_(base::PlatformThread::CurrentId()) {
+  }
+
+  ~DBusStatistics() {
+    DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId());
+    STLDeleteContainerPointers(stats_.begin(), stats_.end());
+  }
+
+  // Enum to specify which field in Stat to increment in AddStat
+  enum StatType {
+    TYPE_SENT_METHOD_CALLS,
+    TYPE_RECEIVED_SIGNALS,
+    TYPE_SENT_BLOCKING_METHOD_CALLS
+  };
+
+  // Add a call to |method| for |interface|. See also MethodCall in message.h.
+  void AddStat(const std::string& service,
+               const std::string& interface,
+               const std::string& method,
+               StatType type) {
+    if (base::PlatformThread::CurrentId() != origin_thread_id_) {
+      DVLOG(1) << "Ignoring DBusStatistics::AddStat call from thread: "
+               << base::PlatformThread::CurrentId();
+      return;
+    }
+    Stat* stat = GetStat(service, interface, method, true);
+    DCHECK(stat);
+    if (type == TYPE_SENT_METHOD_CALLS)
+      ++stat->sent_method_calls;
+    else if (type == TYPE_RECEIVED_SIGNALS)
+      ++stat->received_signals;
+    else if (type == TYPE_SENT_BLOCKING_METHOD_CALLS)
+      ++stat->sent_blocking_method_calls;
+    else
+      NOTREACHED();
+  }
+
+  // Look up the Stat entry in |stats_|. If |add_stat| is true, add a new entry
+  // if one does not already exist.
+  Stat* GetStat(const std::string& service,
+                const std::string& interface,
+                const std::string& method,
+                bool add_stat) {
+    DCHECK_EQ(origin_thread_id_, base::PlatformThread::CurrentId());
+    std::unique_ptr<Stat> stat(new Stat(service, interface, method));
+    StatSet::iterator found = stats_.find(stat.get());
+    if (found != stats_.end())
+      return *found;
+    if (!add_stat)
+      return NULL;
+    found = stats_.insert(stat.release()).first;
+    return *found;
+  }
+
+  StatSet& stats() { return stats_; }
+  base::Time start_time() { return start_time_; }
+
+ private:
+  StatSet stats_;
+  base::Time start_time_;
+  base::PlatformThreadId origin_thread_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusStatistics);
+};
+
+DBusStatistics* g_dbus_statistics = NULL;
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+
+namespace statistics {
+
+void Initialize() {
+  if (g_dbus_statistics)
+    delete g_dbus_statistics;  // reset statistics
+  g_dbus_statistics = new DBusStatistics();
+}
+
+void Shutdown() {
+  delete g_dbus_statistics;
+  g_dbus_statistics = NULL;
+}
+
+void AddSentMethodCall(const std::string& service,
+                       const std::string& interface,
+                       const std::string& method) {
+  if (!g_dbus_statistics)
+    return;
+  g_dbus_statistics->AddStat(
+      service, interface, method, DBusStatistics::TYPE_SENT_METHOD_CALLS);
+}
+
+void AddReceivedSignal(const std::string& service,
+                       const std::string& interface,
+                       const std::string& method) {
+  if (!g_dbus_statistics)
+    return;
+  g_dbus_statistics->AddStat(
+      service, interface, method, DBusStatistics::TYPE_RECEIVED_SIGNALS);
+}
+
+void AddBlockingSentMethodCall(const std::string& service,
+                               const std::string& interface,
+                               const std::string& method) {
+  if (!g_dbus_statistics)
+    return;
+  g_dbus_statistics->AddStat(
+      service, interface, method,
+      DBusStatistics::TYPE_SENT_BLOCKING_METHOD_CALLS);
+}
+
+// NOTE: If the output format is changed, be certain to change the test
+// expectations as well.
+std::string GetAsString(ShowInString show, FormatString format) {
+  if (!g_dbus_statistics)
+    return "DBusStatistics not initialized.";
+
+  const StatSet& stats = g_dbus_statistics->stats();
+  if (stats.empty())
+    return "No DBus calls.";
+
+  base::TimeDelta dtime = base::Time::Now() - g_dbus_statistics->start_time();
+  int dminutes = dtime.InMinutes();
+  dminutes = std::max(dminutes, 1);
+
+  std::string result;
+  int sent = 0, received = 0, sent_blocking = 0;
+  // Stats are stored in order by service, then interface, then method.
+  for (StatSet::const_iterator iter = stats.begin(); iter != stats.end(); ) {
+    StatSet::const_iterator cur_iter = iter;
+    StatSet::const_iterator next_iter = ++iter;
+    const Stat* stat = *cur_iter;
+    sent += stat->sent_method_calls;
+    received += stat->received_signals;
+    sent_blocking += stat->sent_blocking_method_calls;
+    // If this is not the last stat, and if the next stat matches the current
+    // stat, continue.
+    if (next_iter != stats.end() &&
+        (*next_iter)->service == stat->service &&
+        (show < SHOW_INTERFACE || (*next_iter)->interface == stat->interface) &&
+        (show < SHOW_METHOD || (*next_iter)->method == stat->method))
+      continue;
+
+    if (!sent && !received && !sent_blocking)
+        continue;  // No stats collected for this line, skip it and continue.
+
+    // Add a line to the result and clear the counts.
+    std::string line;
+    if (show == SHOW_SERVICE) {
+      line += stat->service;
+    } else {
+      // The interface usually includes the service so don't show both.
+      line += stat->interface;
+      if (show >= SHOW_METHOD)
+        line += "." + stat->method;
+    }
+    line += base::StringPrintf(":");
+    if (sent_blocking) {
+      line += base::StringPrintf(" Sent (BLOCKING):");
+      if (format == FORMAT_TOTALS)
+        line += base::StringPrintf(" %d", sent_blocking);
+      else if (format == FORMAT_PER_MINUTE)
+        line += base::StringPrintf(" %d/min", sent_blocking / dminutes);
+      else if (format == FORMAT_ALL)
+        line += base::StringPrintf(" %d (%d/min)",
+                                   sent_blocking, sent_blocking / dminutes);
+    }
+    if (sent) {
+      line += base::StringPrintf(" Sent:");
+      if (format == FORMAT_TOTALS)
+        line += base::StringPrintf(" %d", sent);
+      else if (format == FORMAT_PER_MINUTE)
+        line += base::StringPrintf(" %d/min", sent / dminutes);
+      else if (format == FORMAT_ALL)
+        line += base::StringPrintf(" %d (%d/min)", sent, sent / dminutes);
+    }
+    if (received) {
+      line += base::StringPrintf(" Received:");
+      if (format == FORMAT_TOTALS)
+        line += base::StringPrintf(" %d", received);
+      else if (format == FORMAT_PER_MINUTE)
+        line += base::StringPrintf(" %d/min", received / dminutes);
+      else if (format == FORMAT_ALL)
+        line += base::StringPrintf(
+            " %d (%d/min)", received, received / dminutes);
+    }
+    result += line + "\n";
+    sent = 0;
+    sent_blocking = 0;
+    received = 0;
+  }
+  return result;
+}
+
+namespace testing {
+
+bool GetCalls(const std::string& service,
+              const std::string& interface,
+              const std::string& method,
+              int* sent,
+              int* received,
+              int* blocking) {
+  if (!g_dbus_statistics)
+    return false;
+  Stat* stat = g_dbus_statistics->GetStat(service, interface, method, false);
+  if (!stat)
+    return false;
+  *sent = stat->sent_method_calls;
+  *received = stat->received_signals;
+  *blocking = stat->sent_blocking_method_calls;
+  return true;
+}
+
+}  // namespace testing
+
+}  // namespace statistics
+}  // namespace dbus
diff --git a/libchrome/dbus/dbus_statistics.h b/libchrome/dbus/dbus_statistics.h
new file mode 100644
index 0000000..e035558
--- /dev/null
+++ b/libchrome/dbus/dbus_statistics.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 DBUS_DBUS_STATISTICS_H_
+#define DBUS_DBUS_STATISTICS_H_
+
+#include <string>
+
+#include "dbus/dbus_export.h"
+
+// The functions defined here are used to gather DBus statistics, and
+// provide them in a format convenient for debugging. These functions are only
+// valid when called from the main thread (the thread which Initialize() was
+// called from). Calls from other threads will be ignored.
+
+namespace dbus {
+namespace statistics {
+
+// Enum to specify what level of detail to show in GetAsString
+enum ShowInString {
+  SHOW_SERVICE = 0,  // Service totals only
+  SHOW_INTERFACE = 1,  // Service + interface totals
+  SHOW_METHOD = 2,  // Service + interface + method totals
+};
+
+// Enum to specify how to format the display in GetAsString
+enum FormatString {
+  FORMAT_TOTALS = 0,  // Raw totals only
+  FORMAT_PER_MINUTE = 1,  // Per-minute only
+  FORMAT_ALL = 2  // Include all format details
+};
+
+// Initializes / shuts down dbus statistics gathering. Calling Initialize
+// more than once will reset the statistics.
+CHROME_DBUS_EXPORT void Initialize();
+CHROME_DBUS_EXPORT void Shutdown();
+
+// Add sent/received calls to the statistics gathering class. These methods
+// do nothing unless Initialize() was called.
+CHROME_DBUS_EXPORT void AddSentMethodCall(const std::string& service,
+                                          const std::string& interface,
+                                          const std::string& method);
+CHROME_DBUS_EXPORT void AddReceivedSignal(const std::string& service,
+                                          const std::string& interface,
+                                          const std::string& method);
+// Track synchronous calls independently since we want to highlight
+// (and remove) these.
+CHROME_DBUS_EXPORT void AddBlockingSentMethodCall(const std::string& service,
+                                                  const std::string& interface,
+                                                  const std::string& method);
+
+// Output the calls into a formatted string. |show| determines what level
+// of detail to show: one line per service, per interface, or per method.
+// If |show_per_minute| is true include per minute stats.
+// Example output for SHOW_METHOD, FORMAT_TOTALS:
+//   org.chromium.Mtpd.EnumerateStorage: Sent: 100
+//   org.chromium.Mtpd.MTPStorageSignal: Received: 20
+// Example output for SHOW_INTERFACE, FORMAT_ALL:
+//   org.chromium.Mtpd: Sent: 100 (10/min) Received: 20 (2/min)
+CHROME_DBUS_EXPORT std::string GetAsString(ShowInString show,
+                                           FormatString format);
+
+namespace testing {
+// Sets |sent| to the number of sent calls, |received| to the number of
+// received calls, and |blocking| to the number of sent blocking calls for
+// service+interface+method. Used in unittests.
+CHROME_DBUS_EXPORT bool GetCalls(const std::string& service,
+                                 const std::string& interface,
+                                 const std::string& method,
+                                 int* sent,
+                                 int* received,
+                                 int* blocking);
+}  // namespace testing
+
+}  // namespace statistics
+}  // namespace dbus
+
+#endif  // DBUS_DBUS_STATISTICS_H_
diff --git a/libchrome/dbus/exported_object.cc b/libchrome/dbus/exported_object.cc
new file mode 100644
index 0000000..b156308
--- /dev/null
+++ b/libchrome/dbus/exported_object.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 "dbus/exported_object.h"
+
+#include <stdint.h>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/scoped_dbus_error.h"
+#include "dbus/util.h"
+
+namespace dbus {
+
+namespace {
+
+// Used for success ratio histograms. 1 for success, 0 for failure.
+const int kSuccessRatioHistogramMaxValue = 2;
+
+}  // namespace
+
+ExportedObject::ExportedObject(Bus* bus,
+                               const ObjectPath& object_path)
+    : bus_(bus),
+      object_path_(object_path),
+      object_is_registered_(false) {
+}
+
+ExportedObject::~ExportedObject() {
+  DCHECK(!object_is_registered_);
+}
+
+bool ExportedObject::ExportMethodAndBlock(
+    const std::string& interface_name,
+    const std::string& method_name,
+    MethodCallCallback method_call_callback) {
+  bus_->AssertOnDBusThread();
+
+  // Check if the method is already exported.
+  const std::string absolute_method_name =
+      GetAbsoluteMemberName(interface_name, method_name);
+  if (method_table_.find(absolute_method_name) != method_table_.end()) {
+    LOG(ERROR) << absolute_method_name << " is already exported";
+    return false;
+  }
+
+  if (!bus_->Connect())
+    return false;
+  if (!bus_->SetUpAsyncOperations())
+    return false;
+  if (!Register())
+    return false;
+
+  // Add the method callback to the method table.
+  method_table_[absolute_method_name] = method_call_callback;
+
+  return true;
+}
+
+void ExportedObject::ExportMethod(const std::string& interface_name,
+                                  const std::string& method_name,
+                                  MethodCallCallback method_call_callback,
+                                  OnExportedCallback on_exported_calback) {
+  bus_->AssertOnOriginThread();
+
+  base::Closure task = base::Bind(&ExportedObject::ExportMethodInternal,
+                                  this,
+                                  interface_name,
+                                  method_name,
+                                  method_call_callback,
+                                  on_exported_calback);
+  bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
+}
+
+void ExportedObject::SendSignal(Signal* signal) {
+  // For signals, the object path should be set to the path to the sender
+  // object, which is this exported object here.
+  CHECK(signal->SetPath(object_path_));
+
+  // Increment the reference count so we can safely reference the
+  // underlying signal message until the signal sending is complete. This
+  // will be unref'ed in SendSignalInternal().
+  DBusMessage* signal_message = signal->raw_message();
+  dbus_message_ref(signal_message);
+
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  if (bus_->GetDBusTaskRunner()->RunsTasksOnCurrentThread()) {
+    // The Chrome OS power manager doesn't use a dedicated TaskRunner for
+    // sending DBus messages.  Sending signals asynchronously can cause an
+    // inversion in the message order if the power manager calls
+    // ObjectProxy::CallMethodAndBlock() before going back to the top level of
+    // the MessageLoop: crbug.com/472361.
+    SendSignalInternal(start_time, signal_message);
+  } else {
+    bus_->GetDBusTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ExportedObject::SendSignalInternal,
+                   this,
+                   start_time,
+                   signal_message));
+  }
+}
+
+void ExportedObject::Unregister() {
+  bus_->AssertOnDBusThread();
+
+  if (!object_is_registered_)
+    return;
+
+  bus_->UnregisterObjectPath(object_path_);
+  object_is_registered_ = false;
+}
+
+void ExportedObject::ExportMethodInternal(
+    const std::string& interface_name,
+    const std::string& method_name,
+    MethodCallCallback method_call_callback,
+    OnExportedCallback on_exported_calback) {
+  bus_->AssertOnDBusThread();
+
+  const bool success = ExportMethodAndBlock(interface_name,
+                                            method_name,
+                                            method_call_callback);
+  bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
+                                        base::Bind(&ExportedObject::OnExported,
+                                                   this,
+                                                   on_exported_calback,
+                                                   interface_name,
+                                                   method_name,
+                                                   success));
+}
+
+void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
+                                const std::string& interface_name,
+                                const std::string& method_name,
+                                bool success) {
+  bus_->AssertOnOriginThread();
+
+  on_exported_callback.Run(interface_name, method_name, success);
+}
+
+void ExportedObject::SendSignalInternal(base::TimeTicks start_time,
+                                        DBusMessage* signal_message) {
+  uint32_t serial = 0;
+  bus_->Send(signal_message, &serial);
+  dbus_message_unref(signal_message);
+  // Record time spent to send the the signal. This is not accurate as the
+  // signal will actually be sent from the next run of the message loop,
+  // but we can at least tell the number of signals sent.
+  UMA_HISTOGRAM_TIMES("DBus.SignalSendTime",
+                      base::TimeTicks::Now() - start_time);
+}
+
+bool ExportedObject::Register() {
+  bus_->AssertOnDBusThread();
+
+  if (object_is_registered_)
+    return true;
+
+  ScopedDBusError error;
+
+  DBusObjectPathVTable vtable = {};
+  vtable.message_function = &ExportedObject::HandleMessageThunk;
+  vtable.unregister_function = &ExportedObject::OnUnregisteredThunk;
+  const bool success = bus_->TryRegisterObjectPath(object_path_,
+                                                   &vtable,
+                                                   this,
+                                                   error.get());
+  if (!success) {
+    LOG(ERROR) << "Failed to register the object: " << object_path_.value()
+               << ": " << (error.is_set() ? error.message() : "");
+    return false;
+  }
+
+  object_is_registered_ = true;
+  return true;
+}
+
+DBusHandlerResult ExportedObject::HandleMessage(DBusConnection*,
+                                                DBusMessage* raw_message) {
+  bus_->AssertOnDBusThread();
+  DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
+
+  // raw_message will be unrefed on exit of the function. Increment the
+  // reference so we can use it in MethodCall.
+  dbus_message_ref(raw_message);
+  std::unique_ptr<MethodCall> method_call(
+      MethodCall::FromRawMessage(raw_message));
+  const std::string interface = method_call->GetInterface();
+  const std::string member = method_call->GetMember();
+
+  if (interface.empty()) {
+    // We don't support method calls without interface.
+    LOG(WARNING) << "Interface is missing: " << method_call->ToString();
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  // Check if we know about the method.
+  const std::string absolute_method_name = GetAbsoluteMemberName(
+      interface, member);
+  MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
+  if (iter == method_table_.end()) {
+    // Don't know about the method.
+    LOG(WARNING) << "Unknown method: " << method_call->ToString();
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  if (bus_->HasDBusThread()) {
+    // Post a task to run the method in the origin thread.
+    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
+                                          base::Bind(&ExportedObject::RunMethod,
+                                                     this,
+                                                     iter->second,
+                                                     base::Passed(&method_call),
+                                                     start_time));
+  } else {
+    // If the D-Bus thread is not used, just call the method directly.
+    MethodCall* method = method_call.get();
+    iter->second.Run(method,
+                     base::Bind(&ExportedObject::SendResponse,
+                                this,
+                                start_time,
+                                base::Passed(&method_call)));
+  }
+
+  // It's valid to say HANDLED here, and send a method response at a later
+  // time from OnMethodCompleted() asynchronously.
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+void ExportedObject::RunMethod(MethodCallCallback method_call_callback,
+                               std::unique_ptr<MethodCall> method_call,
+                               base::TimeTicks start_time) {
+  bus_->AssertOnOriginThread();
+  MethodCall* method = method_call.get();
+  method_call_callback.Run(method,
+                           base::Bind(&ExportedObject::SendResponse,
+                                      this,
+                                      start_time,
+                                      base::Passed(&method_call)));
+}
+
+void ExportedObject::SendResponse(base::TimeTicks start_time,
+                                  std::unique_ptr<MethodCall> method_call,
+                                  std::unique_ptr<Response> response) {
+  DCHECK(method_call);
+  if (bus_->HasDBusThread()) {
+    bus_->GetDBusTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ExportedObject::OnMethodCompleted,
+                   this,
+                   base::Passed(&method_call),
+                   base::Passed(&response),
+                   start_time));
+  } else {
+    OnMethodCompleted(std::move(method_call), std::move(response), start_time);
+  }
+}
+
+void ExportedObject::OnMethodCompleted(std::unique_ptr<MethodCall> method_call,
+                                       std::unique_ptr<Response> response,
+                                       base::TimeTicks start_time) {
+  bus_->AssertOnDBusThread();
+
+  // Record if the method call is successful, or not. 1 if successful.
+  UMA_HISTOGRAM_ENUMERATION("DBus.ExportedMethodHandleSuccess",
+                            response ? 1 : 0,
+                            kSuccessRatioHistogramMaxValue);
+
+  // Check if the bus is still connected. If the method takes long to
+  // complete, the bus may be shut down meanwhile.
+  if (!bus_->is_connected())
+    return;
+
+  if (!response) {
+    // Something bad happened in the method call.
+    std::unique_ptr<ErrorResponse> error_response(ErrorResponse::FromMethodCall(
+        method_call.get(), DBUS_ERROR_FAILED,
+        "error occurred in " + method_call->GetMember()));
+    bus_->Send(error_response->raw_message(), NULL);
+    return;
+  }
+
+  // The method call was successful.
+  bus_->Send(response->raw_message(), NULL);
+
+  // Record time spent to handle the the method call. Don't include failures.
+  UMA_HISTOGRAM_TIMES("DBus.ExportedMethodHandleTime",
+                      base::TimeTicks::Now() - start_time);
+}
+
+void ExportedObject::OnUnregistered(DBusConnection*) {}
+
+DBusHandlerResult ExportedObject::HandleMessageThunk(
+    DBusConnection* connection,
+    DBusMessage* raw_message,
+    void* user_data) {
+  ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
+  return self->HandleMessage(connection, raw_message);
+}
+
+void ExportedObject::OnUnregisteredThunk(DBusConnection *connection,
+                                         void* user_data) {
+  ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
+  return self->OnUnregistered(connection);
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/exported_object.h b/libchrome/dbus/exported_object.h
new file mode 100644
index 0000000..69a63a5
--- /dev/null
+++ b/libchrome/dbus/exported_object.h
@@ -0,0 +1,183 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_EXPORTED_OBJECT_H_
+#define DBUS_EXPORTED_OBJECT_H_
+
+#include <dbus/dbus.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "dbus/dbus_export.h"
+#include "dbus/object_path.h"
+
+namespace dbus {
+
+class Bus;
+class MethodCall;
+class Response;
+class Signal;
+
+// ExportedObject is used to export objects and methods to other D-Bus
+// clients.
+//
+// ExportedObject is a ref counted object, to ensure that |this| of the
+// object is alive when callbacks referencing |this| are called.
+class CHROME_DBUS_EXPORT ExportedObject
+    : public base::RefCountedThreadSafe<ExportedObject> {
+ public:
+  // Client code should use Bus::GetExportedObject() instead of this
+  // constructor.
+  ExportedObject(Bus* bus, const ObjectPath& object_path);
+
+  // Called to send a response from an exported method. |response| is the
+  // response message. Callers should pass NULL in the event of an error that
+  // prevents the sending of a response.
+  typedef base::Callback<void(std::unique_ptr<Response> response)>
+      ResponseSender;
+
+  // Called when an exported method is called. |method_call| is the request
+  // message. |sender| is the callback that's used to send a response.
+  //
+  // |method_call| is owned by ExportedObject, hence client code should not
+  // delete |method_call|.
+  typedef base::Callback<void (MethodCall* method_call, ResponseSender sender)>
+      MethodCallCallback;
+
+  // Called when method exporting is done.
+  // |success| indicates whether exporting was successful or not.
+  typedef base::Callback<void (const std::string& interface_name,
+                               const std::string& method_name,
+                               bool success)>
+      OnExportedCallback;
+
+  // Exports the method specified by |interface_name| and |method_name|,
+  // and blocks until exporting is done. Returns true on success.
+  //
+  // |method_call_callback| will be called in the origin thread, when the
+  // exported method is called. As it's called in the origin thread,
+  // |method_callback| can safely reference objects in the origin thread
+  // (i.e. UI thread in most cases).
+  //
+  // IMPORTANT NOTE: You should export all methods before requesting a
+  // service name by Bus::RequestOwnership/AndBlock(). If you do it in the
+  // wrong order (i.e. request a service name then export methods), there
+  // will be a short time period where your service is unable to respond to
+  // method calls because these methods aren't yet exposed. This race is a
+  // real problem as clients may start calling methods of your service as
+  // soon as you acquire a service name, by watching the name owner change.
+  //
+  // BLOCKING CALL.
+  virtual bool ExportMethodAndBlock(const std::string& interface_name,
+                                    const std::string& method_name,
+                                    MethodCallCallback method_call_callback);
+
+  // Requests to export the method specified by |interface_name| and
+  // |method_name|. See Also ExportMethodAndBlock().
+  //
+  // |on_exported_callback| is called when the method is exported or
+  // failed to be exported, in the origin thread.
+  //
+  // Must be called in the origin thread.
+  virtual void ExportMethod(const std::string& interface_name,
+                            const std::string& method_name,
+                            MethodCallCallback method_call_callback,
+                            OnExportedCallback on_exported_callback);
+
+  // Requests to send the signal from this object. The signal will be sent
+  // synchronously if this method is called from the message loop in the D-Bus
+  // thread and asynchronously otherwise.
+  virtual void SendSignal(Signal* signal);
+
+  // Unregisters the object from the bus. The Bus object will take care of
+  // unregistering so you don't have to do this manually.
+  //
+  // BLOCKING CALL.
+  virtual void Unregister();
+
+ protected:
+  // This is protected, so we can define sub classes.
+  virtual ~ExportedObject();
+
+ private:
+  friend class base::RefCountedThreadSafe<ExportedObject>;
+
+  // Helper function for ExportMethod().
+  void ExportMethodInternal(const std::string& interface_name,
+                            const std::string& method_name,
+                            MethodCallCallback method_call_callback,
+                            OnExportedCallback exported_callback);
+
+  // Called when the object is exported.
+  void OnExported(OnExportedCallback on_exported_callback,
+                  const std::string& interface_name,
+                  const std::string& method_name,
+                  bool success);
+
+  // Helper function for SendSignal().
+  void SendSignalInternal(base::TimeTicks start_time,
+                          DBusMessage* signal_message);
+
+  // Registers this object to the bus.
+  // Returns true on success, or the object is already registered.
+  //
+  // BLOCKING CALL.
+  bool Register();
+
+  // Handles the incoming request messages and dispatches to the exported
+  // methods.
+  DBusHandlerResult HandleMessage(DBusConnection* connection,
+                                  DBusMessage* raw_message);
+
+  // Runs the method. Helper function for HandleMessage().
+  void RunMethod(MethodCallCallback method_call_callback,
+                 std::unique_ptr<MethodCall> method_call,
+                 base::TimeTicks start_time);
+
+  // Callback invoked by service provider to send a response to a method call.
+  // Can be called immediately from a MethodCallCallback to implement a
+  // synchronous service or called later to implement an asynchronous service.
+  void SendResponse(base::TimeTicks start_time,
+                    std::unique_ptr<MethodCall> method_call,
+                    std::unique_ptr<Response> response);
+
+  // Called on completion of the method run from SendResponse().
+  // Takes ownership of |method_call| and |response|.
+  void OnMethodCompleted(std::unique_ptr<MethodCall> method_call,
+                         std::unique_ptr<Response> response,
+                         base::TimeTicks start_time);
+
+  // Called when the object is unregistered.
+  void OnUnregistered(DBusConnection* connection);
+
+  // Redirects the function call to HandleMessage().
+  static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
+                                              DBusMessage* raw_message,
+                                              void* user_data);
+
+  // Redirects the function call to OnUnregistered().
+  static void OnUnregisteredThunk(DBusConnection* connection,
+                                  void* user_data);
+
+  scoped_refptr<Bus> bus_;
+  ObjectPath object_path_;
+  bool object_is_registered_;
+
+  // The method table where keys are absolute method names (i.e. interface
+  // name + method name), and values are the corresponding callbacks.
+  typedef std::map<std::string, MethodCallCallback> MethodTable;
+  MethodTable method_table_;
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_EXPORTED_OBJECT_H_
diff --git a/libchrome/dbus/file_descriptor.cc b/libchrome/dbus/file_descriptor.cc
new file mode 100644
index 0000000..b690881
--- /dev/null
+++ b/libchrome/dbus/file_descriptor.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 <algorithm>
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/threading/worker_pool.h"
+#include "dbus/file_descriptor.h"
+
+using std::swap;
+
+namespace dbus {
+
+void CHROME_DBUS_EXPORT FileDescriptor::Deleter::operator()(
+    FileDescriptor* fd) {
+  base::WorkerPool::PostTask(
+      FROM_HERE, base::Bind(&base::DeletePointer<FileDescriptor>, fd), false);
+}
+
+FileDescriptor::FileDescriptor(FileDescriptor&& other) : FileDescriptor() {
+  Swap(&other);
+}
+
+FileDescriptor::~FileDescriptor() {
+  if (owner_)
+    base::File auto_closer(value_);
+}
+
+FileDescriptor& FileDescriptor::operator=(FileDescriptor&& other) {
+  Swap(&other);
+  return *this;
+}
+
+int FileDescriptor::value() const {
+  CHECK(valid_);
+  return value_;
+}
+
+int FileDescriptor::TakeValue() {
+  CHECK(valid_);  // NB: check first so owner_ is unchanged if this triggers
+  owner_ = false;
+  return value_;
+}
+
+void FileDescriptor::CheckValidity() {
+  base::File file(value_);
+  if (!file.IsValid()) {
+    valid_ = false;
+    return;
+  }
+
+  base::File::Info info;
+  bool ok = file.GetInfo(&info);
+  file.TakePlatformFile();  // Prevent |value_| from being closed by |file|.
+  valid_ = (ok && !info.is_directory);
+}
+
+void FileDescriptor::Swap(FileDescriptor* other) {
+  swap(value_, other->value_);
+  swap(owner_, other->owner_);
+  swap(valid_, other->valid_);
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/file_descriptor.h b/libchrome/dbus/file_descriptor.h
new file mode 100644
index 0000000..f8e8677
--- /dev/null
+++ b/libchrome/dbus/file_descriptor.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 DBUS_FILE_DESCRIPTOR_H_
+#define DBUS_FILE_DESCRIPTOR_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "dbus/dbus_export.h"
+
+namespace dbus {
+
+// FileDescriptor is a type used to encapsulate D-Bus file descriptors
+// and to follow the RAII idiom appropiate for use with message operations
+// where the descriptor might be easily leaked.  To guard against this the
+// descriptor is closed when an instance is destroyed if it is owned.
+// Ownership is asserted only when PutValue is used and TakeValue can be
+// used to take ownership.
+//
+// For example, in the following
+//  FileDescriptor fd;
+//  if (!reader->PopString(&name) ||
+//      !reader->PopFileDescriptor(&fd) ||
+//      !reader->PopUint32(&flags)) {
+// the descriptor in fd will be closed if the PopUint32 fails.  But
+//   writer.AppendFileDescriptor(dbus::FileDescriptor(1));
+// will not automatically close "1" because it is not owned.
+//
+// Descriptors must be validated before marshalling in a D-Bus message
+// or using them after unmarshalling.  We disallow descriptors to a
+// directory to reduce the security risks.  Splitting out validation
+// also allows the caller to do this work on the File thread to conform
+// with i/o restrictions.
+class CHROME_DBUS_EXPORT FileDescriptor {
+ public:
+  // This provides a simple way to pass around file descriptors since they must
+  // be closed on a thread that is allowed to perform I/O.
+  struct Deleter {
+    void CHROME_DBUS_EXPORT operator()(FileDescriptor* fd);
+  };
+
+  // Permits initialization without a value for passing to
+  // dbus::MessageReader::PopFileDescriptor to fill in and from int values.
+  FileDescriptor() : value_(-1), owner_(false), valid_(false) {}
+  explicit FileDescriptor(int value) : value_(value), owner_(false),
+      valid_(false) {}
+
+  FileDescriptor(FileDescriptor&& other);
+
+  virtual ~FileDescriptor();
+
+  FileDescriptor& operator=(FileDescriptor&& other);
+
+  // Retrieves value as an int without affecting ownership.
+  int value() const;
+
+  // Retrieves whether or not the descriptor is ok to send/receive.
+  int is_valid() const { return valid_; }
+
+  // Sets the value and assign ownership.
+  void PutValue(int value) {
+    value_ = value;
+    owner_ = true;
+    valid_ = false;
+  }
+
+  // Takes the value and ownership.
+  int TakeValue();
+
+  // Checks (and records) validity of the file descriptor.
+  // We disallow directories to avoid potential sandbox escapes.
+  // Note this call must be made on a thread where file i/o is allowed.
+  void CheckValidity();
+
+ private:
+  void Swap(FileDescriptor* other);
+
+  int value_;
+  bool owner_;
+  bool valid_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptor);
+};
+
+using ScopedFileDescriptor =
+    std::unique_ptr<FileDescriptor, FileDescriptor::Deleter>;
+
+}  // namespace dbus
+
+#endif  // DBUS_FILE_DESCRIPTOR_H_
diff --git a/libchrome/dbus/message.cc b/libchrome/dbus/message.cc
new file mode 100644
index 0000000..aca9055
--- /dev/null
+++ b/libchrome/dbus/message.cc
@@ -0,0 +1,997 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/message.h"
+
+#include <string>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "dbus/object_path.h"
+
+namespace {
+
+// Appends the header name and the value to |output|, if the value is
+// not empty.
+void AppendStringHeader(const std::string& header_name,
+                        const std::string& header_value,
+                        std::string* output) {
+  if (!header_value.empty()) {
+    *output += header_name + ": " + header_value + "\n";
+  }
+}
+
+// Appends the header name and the value to |output|, if the value is
+// nonzero.
+void AppendUint32Header(const std::string& header_name,
+                        uint32_t header_value,
+                        std::string* output) {
+  if (header_value != 0) {
+    *output += (header_name + ": " + base::UintToString(header_value) + "\n");
+  }
+}
+
+}  // namespace
+
+namespace dbus {
+
+bool IsDBusTypeUnixFdSupported() {
+  int major = 0, minor = 0, micro = 0;
+  dbus_get_version(&major, &minor, &micro);
+  return major >= 1 && minor >= 4;
+}
+
+Message::Message()
+    : raw_message_(NULL) {
+}
+
+Message::~Message() {
+  if (raw_message_)
+    dbus_message_unref(raw_message_);
+}
+
+void Message::Init(DBusMessage* raw_message) {
+  DCHECK(!raw_message_);
+  raw_message_ = raw_message;
+}
+
+Message::MessageType Message::GetMessageType() {
+  if (!raw_message_)
+    return MESSAGE_INVALID;
+  const int type = dbus_message_get_type(raw_message_);
+  return static_cast<Message::MessageType>(type);
+}
+
+std::string Message::GetMessageTypeAsString() {
+  switch (GetMessageType()) {
+    case MESSAGE_INVALID:
+      return "MESSAGE_INVALID";
+    case MESSAGE_METHOD_CALL:
+      return "MESSAGE_METHOD_CALL";
+    case MESSAGE_METHOD_RETURN:
+      return "MESSAGE_METHOD_RETURN";
+    case MESSAGE_SIGNAL:
+      return "MESSAGE_SIGNAL";
+    case MESSAGE_ERROR:
+      return "MESSAGE_ERROR";
+  }
+  NOTREACHED();
+  return std::string();
+}
+
+std::string Message::ToStringInternal(const std::string& indent,
+                                      MessageReader* reader) {
+  const char* kBrokenMessage = "[broken message]";
+  std::string output;
+  while (reader->HasMoreData()) {
+    const DataType type = reader->GetDataType();
+    switch (type) {
+      case BYTE: {
+        uint8_t value = 0;
+        if (!reader->PopByte(&value))
+          return kBrokenMessage;
+        output += indent + "byte " + base::UintToString(value) + "\n";
+        break;
+      }
+      case BOOL: {
+        bool value = false;
+        if (!reader->PopBool(&value))
+          return kBrokenMessage;
+        output += indent + "bool " + (value ? "true" : "false") + "\n";
+        break;
+      }
+      case INT16: {
+        int16_t value = 0;
+        if (!reader->PopInt16(&value))
+          return kBrokenMessage;
+        output += indent + "int16_t " + base::IntToString(value) + "\n";
+        break;
+      }
+      case UINT16: {
+        uint16_t value = 0;
+        if (!reader->PopUint16(&value))
+          return kBrokenMessage;
+        output += indent + "uint16_t " + base::UintToString(value) + "\n";
+        break;
+      }
+      case INT32: {
+        int32_t value = 0;
+        if (!reader->PopInt32(&value))
+          return kBrokenMessage;
+        output += indent + "int32_t " + base::IntToString(value) + "\n";
+        break;
+      }
+      case UINT32: {
+        uint32_t value = 0;
+        if (!reader->PopUint32(&value))
+          return kBrokenMessage;
+        output += indent + "uint32_t " + base::UintToString(value) + "\n";
+        break;
+      }
+      case INT64: {
+        int64_t value = 0;
+        if (!reader->PopInt64(&value))
+          return kBrokenMessage;
+        output += (indent + "int64_t " + base::Int64ToString(value) + "\n");
+        break;
+      }
+      case UINT64: {
+        uint64_t value = 0;
+        if (!reader->PopUint64(&value))
+          return kBrokenMessage;
+        output += (indent + "uint64_t " + base::Uint64ToString(value) + "\n");
+        break;
+      }
+      case DOUBLE: {
+        double value = 0;
+        if (!reader->PopDouble(&value))
+          return kBrokenMessage;
+        output += indent + "double " + base::DoubleToString(value) + "\n";
+        break;
+      }
+      case STRING: {
+        std::string value;
+        if (!reader->PopString(&value))
+          return kBrokenMessage;
+        // Truncate if the string is longer than the limit.
+        const size_t kTruncateLength = 100;
+        if (value.size() < kTruncateLength) {
+          output += indent + "string \"" + value + "\"\n";
+        } else {
+          std::string truncated;
+          base::TruncateUTF8ToByteSize(value, kTruncateLength, &truncated);
+          base::StringAppendF(&truncated, "... (%" PRIuS " bytes in total)",
+                              value.size());
+          output += indent + "string \"" + truncated + "\"\n";
+        }
+        break;
+      }
+      case OBJECT_PATH: {
+        ObjectPath value;
+        if (!reader->PopObjectPath(&value))
+          return kBrokenMessage;
+        output += indent + "object_path \"" + value.value() + "\"\n";
+        break;
+      }
+      case ARRAY: {
+        MessageReader sub_reader(this);
+        if (!reader->PopArray(&sub_reader))
+          return kBrokenMessage;
+        output += indent + "array [\n";
+        output += ToStringInternal(indent + "  ", &sub_reader);
+        output += indent + "]\n";
+        break;
+      }
+      case STRUCT: {
+        MessageReader sub_reader(this);
+        if (!reader->PopStruct(&sub_reader))
+          return kBrokenMessage;
+        output += indent + "struct {\n";
+        output += ToStringInternal(indent + "  ", &sub_reader);
+        output += indent + "}\n";
+        break;
+      }
+      case DICT_ENTRY: {
+        MessageReader sub_reader(this);
+        if (!reader->PopDictEntry(&sub_reader))
+          return kBrokenMessage;
+        output += indent + "dict entry {\n";
+        output += ToStringInternal(indent + "  ", &sub_reader);
+        output += indent + "}\n";
+        break;
+      }
+      case VARIANT: {
+        MessageReader sub_reader(this);
+        if (!reader->PopVariant(&sub_reader))
+          return kBrokenMessage;
+        output += indent + "variant ";
+        output += ToStringInternal(indent + "  ", &sub_reader);
+        break;
+      }
+      case UNIX_FD: {
+        CHECK(IsDBusTypeUnixFdSupported());
+
+        FileDescriptor file_descriptor;
+        if (!reader->PopFileDescriptor(&file_descriptor))
+          return kBrokenMessage;
+        output += indent + "fd#" +
+                  base::IntToString(file_descriptor.value()) + "\n";
+        break;
+      }
+      default:
+        LOG(FATAL) << "Unknown type: " << type;
+    }
+  }
+  return output;
+}
+
+// The returned string consists of message headers such as
+// destination if any, followed by a blank line, and the message
+// payload. For example, a MethodCall's ToString() will look like:
+//
+// destination: com.example.Service
+// path: /com/example/Object
+// interface: com.example.Interface
+// member: SomeMethod
+//
+// string \"payload\"
+// ...
+std::string Message::ToString() {
+  if (!raw_message_)
+    return std::string();
+
+  // Generate headers first.
+  std::string headers;
+  AppendStringHeader("message_type", GetMessageTypeAsString(), &headers);
+  AppendStringHeader("destination", GetDestination(), &headers);
+  AppendStringHeader("path", GetPath().value(), &headers);
+  AppendStringHeader("interface", GetInterface(), &headers);
+  AppendStringHeader("member", GetMember(), &headers);
+  AppendStringHeader("error_name", GetErrorName(), &headers);
+  AppendStringHeader("sender", GetSender(), &headers);
+  AppendStringHeader("signature", GetSignature(), &headers);
+  AppendUint32Header("serial", GetSerial(), &headers);
+  AppendUint32Header("reply_serial", GetReplySerial(), &headers);
+
+  // Generate the payload.
+  MessageReader reader(this);
+  return headers + "\n" + ToStringInternal(std::string(), &reader);
+}
+
+bool Message::SetDestination(const std::string& destination) {
+  return dbus_message_set_destination(raw_message_, destination.c_str());
+}
+
+bool Message::SetPath(const ObjectPath& path) {
+  return dbus_message_set_path(raw_message_, path.value().c_str());
+}
+
+bool Message::SetInterface(const std::string& interface) {
+  return dbus_message_set_interface(raw_message_, interface.c_str());
+}
+
+bool Message::SetMember(const std::string& member) {
+  return dbus_message_set_member(raw_message_, member.c_str());
+}
+
+bool Message::SetErrorName(const std::string& error_name) {
+  return dbus_message_set_error_name(raw_message_, error_name.c_str());
+}
+
+bool Message::SetSender(const std::string& sender) {
+  return dbus_message_set_sender(raw_message_, sender.c_str());
+}
+
+void Message::SetSerial(uint32_t serial) {
+  dbus_message_set_serial(raw_message_, serial);
+}
+
+void Message::SetReplySerial(uint32_t reply_serial) {
+  dbus_message_set_reply_serial(raw_message_, reply_serial);
+}
+
+std::string Message::GetDestination() {
+  const char* destination = dbus_message_get_destination(raw_message_);
+  return destination ? destination : "";
+}
+
+ObjectPath Message::GetPath() {
+  const char* path = dbus_message_get_path(raw_message_);
+  return ObjectPath(path ? path : "");
+}
+
+std::string Message::GetInterface() {
+  const char* interface = dbus_message_get_interface(raw_message_);
+  return interface ? interface : "";
+}
+
+std::string Message::GetMember() {
+  const char* member = dbus_message_get_member(raw_message_);
+  return member ? member : "";
+}
+
+std::string Message::GetErrorName() {
+  const char* error_name = dbus_message_get_error_name(raw_message_);
+  return error_name ? error_name : "";
+}
+
+std::string Message::GetSender() {
+  const char* sender = dbus_message_get_sender(raw_message_);
+  return sender ? sender : "";
+}
+
+std::string Message::GetSignature() {
+  const char* signature = dbus_message_get_signature(raw_message_);
+  return signature ? signature : "";
+}
+
+uint32_t Message::GetSerial() {
+  return dbus_message_get_serial(raw_message_);
+}
+
+uint32_t Message::GetReplySerial() {
+  return dbus_message_get_reply_serial(raw_message_);
+}
+
+//
+// MethodCall implementation.
+//
+
+MethodCall::MethodCall(const std::string& interface_name,
+                       const std::string& method_name)
+    : Message() {
+  Init(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL));
+
+  CHECK(SetInterface(interface_name));
+  CHECK(SetMember(method_name));
+}
+
+MethodCall::MethodCall() : Message() {
+}
+
+MethodCall* MethodCall::FromRawMessage(DBusMessage* raw_message) {
+  DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
+
+  MethodCall* method_call = new MethodCall;
+  method_call->Init(raw_message);
+  return method_call;
+}
+
+//
+// Signal implementation.
+//
+Signal::Signal(const std::string& interface_name,
+               const std::string& method_name)
+    : Message() {
+  Init(dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL));
+
+  CHECK(SetInterface(interface_name));
+  CHECK(SetMember(method_name));
+}
+
+Signal::Signal() : Message() {
+}
+
+Signal* Signal::FromRawMessage(DBusMessage* raw_message) {
+  DCHECK_EQ(DBUS_MESSAGE_TYPE_SIGNAL, dbus_message_get_type(raw_message));
+
+  Signal* signal = new Signal;
+  signal->Init(raw_message);
+  return signal;
+}
+
+//
+// Response implementation.
+//
+
+Response::Response() : Message() {
+}
+
+std::unique_ptr<Response> Response::FromRawMessage(DBusMessage* raw_message) {
+  DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_RETURN,
+            dbus_message_get_type(raw_message));
+
+  std::unique_ptr<Response> response(new Response);
+  response->Init(raw_message);
+  return response;
+}
+
+std::unique_ptr<Response> Response::FromMethodCall(MethodCall* method_call) {
+  std::unique_ptr<Response> response(new Response);
+  response->Init(dbus_message_new_method_return(method_call->raw_message()));
+  return response;
+}
+
+std::unique_ptr<Response> Response::CreateEmpty() {
+  std::unique_ptr<Response> response(new Response);
+  response->Init(dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN));
+  return response;
+}
+
+//
+// ErrorResponse implementation.
+//
+
+ErrorResponse::ErrorResponse() : Response() {
+}
+
+std::unique_ptr<ErrorResponse> ErrorResponse::FromRawMessage(
+    DBusMessage* raw_message) {
+  DCHECK_EQ(DBUS_MESSAGE_TYPE_ERROR, dbus_message_get_type(raw_message));
+
+  std::unique_ptr<ErrorResponse> response(new ErrorResponse);
+  response->Init(raw_message);
+  return response;
+}
+
+std::unique_ptr<ErrorResponse> ErrorResponse::FromMethodCall(
+    MethodCall* method_call,
+    const std::string& error_name,
+    const std::string& error_message) {
+  std::unique_ptr<ErrorResponse> response(new ErrorResponse);
+  response->Init(dbus_message_new_error(method_call->raw_message(),
+                                        error_name.c_str(),
+                                        error_message.c_str()));
+  return response;
+}
+
+//
+// MessageWriter implementation.
+//
+
+MessageWriter::MessageWriter(Message* message)
+    : message_(message),
+      container_is_open_(false) {
+  memset(&raw_message_iter_, 0, sizeof(raw_message_iter_));
+  if (message)
+    dbus_message_iter_init_append(message_->raw_message(), &raw_message_iter_);
+}
+
+MessageWriter::~MessageWriter() {
+}
+
+void MessageWriter::AppendByte(uint8_t value) {
+  AppendBasic(DBUS_TYPE_BYTE, &value);
+}
+
+void MessageWriter::AppendBool(bool value) {
+  // The size of dbus_bool_t and the size of bool are different. The
+  // former is always 4 per dbus-types.h, whereas the latter is usually 1.
+  // dbus_message_iter_append_basic() used in AppendBasic() expects four
+  // bytes for DBUS_TYPE_BOOLEAN, so we must pass a dbus_bool_t, instead
+  // of a bool, to AppendBasic().
+  dbus_bool_t dbus_value = value;
+  AppendBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
+}
+
+void MessageWriter::AppendInt16(int16_t value) {
+  AppendBasic(DBUS_TYPE_INT16, &value);
+}
+
+void MessageWriter::AppendUint16(uint16_t value) {
+  AppendBasic(DBUS_TYPE_UINT16, &value);
+}
+
+void MessageWriter::AppendInt32(int32_t value) {
+  AppendBasic(DBUS_TYPE_INT32, &value);
+}
+
+void MessageWriter::AppendUint32(uint32_t value) {
+  AppendBasic(DBUS_TYPE_UINT32, &value);
+}
+
+void MessageWriter::AppendInt64(int64_t value) {
+  AppendBasic(DBUS_TYPE_INT64, &value);
+}
+
+void MessageWriter::AppendUint64(uint64_t value) {
+  AppendBasic(DBUS_TYPE_UINT64, &value);
+}
+
+void MessageWriter::AppendDouble(double value) {
+  AppendBasic(DBUS_TYPE_DOUBLE, &value);
+}
+
+void MessageWriter::AppendString(const std::string& value) {
+  // D-Bus Specification (0.19) says a string "must be valid UTF-8".
+  CHECK(base::IsStringUTF8(value));
+  const char* pointer = value.c_str();
+  AppendBasic(DBUS_TYPE_STRING, &pointer);
+  // TODO(satorux): It may make sense to return an error here, as the
+  // input string can be large. If needed, we could add something like
+  // bool AppendStringWithErrorChecking().
+}
+
+void MessageWriter::AppendObjectPath(const ObjectPath& value) {
+  CHECK(value.IsValid());
+  const char* pointer = value.value().c_str();
+  AppendBasic(DBUS_TYPE_OBJECT_PATH, &pointer);
+}
+
+// Ideally, client shouldn't need to supply the signature string, but
+// the underlying D-Bus library requires us to supply this before
+// appending contents to array and variant. It's technically possible
+// for us to design API that doesn't require the signature but it will
+// complicate the implementation so we decided to have the signature
+// parameter. Hopefully, variants are less used in request messages from
+// client side than response message from server side, so this should
+// not be a big issue.
+void MessageWriter::OpenArray(const std::string& signature,
+                              MessageWriter* writer) {
+  DCHECK(!container_is_open_);
+
+  const bool success = dbus_message_iter_open_container(
+      &raw_message_iter_,
+      DBUS_TYPE_ARRAY,
+      signature.c_str(),
+      &writer->raw_message_iter_);
+  CHECK(success) << "Unable to allocate memory";
+  container_is_open_ = true;
+}
+
+void MessageWriter::OpenVariant(const std::string& signature,
+                                MessageWriter* writer) {
+  DCHECK(!container_is_open_);
+
+  const bool success = dbus_message_iter_open_container(
+      &raw_message_iter_,
+      DBUS_TYPE_VARIANT,
+      signature.c_str(),
+      &writer->raw_message_iter_);
+  CHECK(success) << "Unable to allocate memory";
+  container_is_open_ = true;
+}
+
+void MessageWriter::OpenStruct(MessageWriter* writer) {
+  DCHECK(!container_is_open_);
+
+  const bool success = dbus_message_iter_open_container(
+      &raw_message_iter_,
+      DBUS_TYPE_STRUCT,
+      NULL,  // Signature should be NULL.
+      &writer->raw_message_iter_);
+  CHECK(success) << "Unable to allocate memory";
+  container_is_open_ = true;
+}
+
+void MessageWriter::OpenDictEntry(MessageWriter* writer) {
+  DCHECK(!container_is_open_);
+
+  const bool success = dbus_message_iter_open_container(
+      &raw_message_iter_,
+      DBUS_TYPE_DICT_ENTRY,
+      NULL,  // Signature should be NULL.
+      &writer->raw_message_iter_);
+  CHECK(success) << "Unable to allocate memory";
+  container_is_open_ = true;
+}
+
+void MessageWriter::CloseContainer(MessageWriter* writer) {
+  DCHECK(container_is_open_);
+
+  const bool success = dbus_message_iter_close_container(
+      &raw_message_iter_, &writer->raw_message_iter_);
+  CHECK(success) << "Unable to allocate memory";
+  container_is_open_ = false;
+}
+
+void MessageWriter::AppendArrayOfBytes(const uint8_t* values, size_t length) {
+  DCHECK(!container_is_open_);
+  MessageWriter array_writer(message_);
+  OpenArray("y", &array_writer);
+  const bool success = dbus_message_iter_append_fixed_array(
+      &(array_writer.raw_message_iter_),
+      DBUS_TYPE_BYTE,
+      &values,
+      static_cast<int>(length));
+  CHECK(success) << "Unable to allocate memory";
+  CloseContainer(&array_writer);
+}
+
+void MessageWriter::AppendArrayOfDoubles(const double* values, size_t length) {
+  DCHECK(!container_is_open_);
+  MessageWriter array_writer(message_);
+  OpenArray("d", &array_writer);
+  const bool success = dbus_message_iter_append_fixed_array(
+      &(array_writer.raw_message_iter_),
+      DBUS_TYPE_DOUBLE,
+      &values,
+      static_cast<int>(length));
+  CHECK(success) << "Unable to allocate memory";
+  CloseContainer(&array_writer);
+}
+
+void MessageWriter::AppendArrayOfStrings(
+    const std::vector<std::string>& strings) {
+  DCHECK(!container_is_open_);
+  MessageWriter array_writer(message_);
+  OpenArray("s", &array_writer);
+  for (size_t i = 0; i < strings.size(); ++i) {
+    array_writer.AppendString(strings[i]);
+  }
+  CloseContainer(&array_writer);
+}
+
+void MessageWriter::AppendArrayOfObjectPaths(
+    const std::vector<ObjectPath>& object_paths) {
+  DCHECK(!container_is_open_);
+  MessageWriter array_writer(message_);
+  OpenArray("o", &array_writer);
+  for (size_t i = 0; i < object_paths.size(); ++i) {
+    array_writer.AppendObjectPath(object_paths[i]);
+  }
+  CloseContainer(&array_writer);
+}
+
+void MessageWriter::AppendVariantOfByte(uint8_t value) {
+  AppendVariantOfBasic(DBUS_TYPE_BYTE, &value);
+}
+
+void MessageWriter::AppendVariantOfBool(bool value) {
+  // See the comment at MessageWriter::AppendBool().
+  dbus_bool_t dbus_value = value;
+  AppendVariantOfBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
+}
+
+void MessageWriter::AppendVariantOfInt16(int16_t value) {
+  AppendVariantOfBasic(DBUS_TYPE_INT16, &value);
+}
+
+void MessageWriter::AppendVariantOfUint16(uint16_t value) {
+  AppendVariantOfBasic(DBUS_TYPE_UINT16, &value);
+}
+
+void MessageWriter::AppendVariantOfInt32(int32_t value) {
+  AppendVariantOfBasic(DBUS_TYPE_INT32, &value);
+}
+
+void MessageWriter::AppendVariantOfUint32(uint32_t value) {
+  AppendVariantOfBasic(DBUS_TYPE_UINT32, &value);
+}
+
+void MessageWriter::AppendVariantOfInt64(int64_t value) {
+  AppendVariantOfBasic(DBUS_TYPE_INT64, &value);
+}
+
+void MessageWriter::AppendVariantOfUint64(uint64_t value) {
+  AppendVariantOfBasic(DBUS_TYPE_UINT64, &value);
+}
+
+void MessageWriter::AppendVariantOfDouble(double value) {
+  AppendVariantOfBasic(DBUS_TYPE_DOUBLE, &value);
+}
+
+void MessageWriter::AppendVariantOfString(const std::string& value) {
+  const char* pointer = value.c_str();
+  AppendVariantOfBasic(DBUS_TYPE_STRING, &pointer);
+}
+
+void MessageWriter::AppendVariantOfObjectPath(const ObjectPath& value) {
+  const char* pointer = value.value().c_str();
+  AppendVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &pointer);
+}
+
+void MessageWriter::AppendBasic(int dbus_type, const void* value) {
+  DCHECK(!container_is_open_);
+
+  const bool success = dbus_message_iter_append_basic(
+      &raw_message_iter_, dbus_type, value);
+  // dbus_message_iter_append_basic() fails only when there is not enough
+  // memory. We don't return this error as there is nothing we can do when
+  // it fails to allocate memory for a byte etc.
+  CHECK(success) << "Unable to allocate memory";
+}
+
+void MessageWriter::AppendVariantOfBasic(int dbus_type, const void* value) {
+  const std::string signature(1u,  // length
+                              base::checked_cast<char>(dbus_type));
+  MessageWriter variant_writer(message_);
+  OpenVariant(signature, &variant_writer);
+  variant_writer.AppendBasic(dbus_type, value);
+  CloseContainer(&variant_writer);
+}
+
+void MessageWriter::AppendFileDescriptor(const FileDescriptor& value) {
+  CHECK(IsDBusTypeUnixFdSupported());
+
+  if (!value.is_valid()) {
+    // NB: sending a directory potentially enables sandbox escape
+    LOG(FATAL) << "Attempt to pass invalid file descriptor";
+  }
+  int fd = value.value();
+  AppendBasic(DBUS_TYPE_UNIX_FD, &fd);
+}
+
+//
+// MessageReader implementation.
+//
+
+MessageReader::MessageReader(Message* message)
+    : message_(message) {
+  memset(&raw_message_iter_, 0, sizeof(raw_message_iter_));
+  if (message)
+    dbus_message_iter_init(message_->raw_message(), &raw_message_iter_);
+}
+
+
+MessageReader::~MessageReader() {
+}
+
+bool MessageReader::HasMoreData() {
+  const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
+  return dbus_type != DBUS_TYPE_INVALID;
+}
+
+bool MessageReader::PopByte(uint8_t* value) {
+  return PopBasic(DBUS_TYPE_BYTE, value);
+}
+
+bool MessageReader::PopBool(bool* value) {
+  // Like MessageWriter::AppendBool(), we should copy |value| to
+  // dbus_bool_t, as dbus_message_iter_get_basic() used in PopBasic()
+  // expects four bytes for DBUS_TYPE_BOOLEAN.
+  dbus_bool_t dbus_value = FALSE;
+  const bool success = PopBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
+  *value = static_cast<bool>(dbus_value);
+  return success;
+}
+
+bool MessageReader::PopInt16(int16_t* value) {
+  return PopBasic(DBUS_TYPE_INT16, value);
+}
+
+bool MessageReader::PopUint16(uint16_t* value) {
+  return PopBasic(DBUS_TYPE_UINT16, value);
+}
+
+bool MessageReader::PopInt32(int32_t* value) {
+  return PopBasic(DBUS_TYPE_INT32, value);
+}
+
+bool MessageReader::PopUint32(uint32_t* value) {
+  return PopBasic(DBUS_TYPE_UINT32, value);
+}
+
+bool MessageReader::PopInt64(int64_t* value) {
+  return PopBasic(DBUS_TYPE_INT64, value);
+}
+
+bool MessageReader::PopUint64(uint64_t* value) {
+  return PopBasic(DBUS_TYPE_UINT64, value);
+}
+
+bool MessageReader::PopDouble(double* value) {
+  return PopBasic(DBUS_TYPE_DOUBLE, value);
+}
+
+bool MessageReader::PopString(std::string* value) {
+  char* tmp_value = NULL;
+  const bool success = PopBasic(DBUS_TYPE_STRING, &tmp_value);
+  if (success)
+    value->assign(tmp_value);
+  return success;
+}
+
+bool MessageReader::PopObjectPath(ObjectPath* value) {
+  char* tmp_value = NULL;
+  const bool success = PopBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
+  if (success)
+    *value = ObjectPath(tmp_value);
+  return success;
+}
+
+bool MessageReader::PopArray(MessageReader* sub_reader) {
+  return PopContainer(DBUS_TYPE_ARRAY, sub_reader);
+}
+
+bool MessageReader::PopStruct(MessageReader* sub_reader) {
+  return PopContainer(DBUS_TYPE_STRUCT, sub_reader);
+}
+
+bool MessageReader::PopDictEntry(MessageReader* sub_reader) {
+  return PopContainer(DBUS_TYPE_DICT_ENTRY, sub_reader);
+}
+
+bool MessageReader::PopVariant(MessageReader* sub_reader) {
+  return PopContainer(DBUS_TYPE_VARIANT, sub_reader);
+}
+
+bool MessageReader::PopArrayOfBytes(const uint8_t** bytes, size_t* length) {
+  MessageReader array_reader(message_);
+  if (!PopArray(&array_reader))
+      return false;
+  // An empty array is allowed.
+  if (!array_reader.HasMoreData()) {
+    *length = 0;
+    *bytes = NULL;
+    return true;
+  }
+  if (!array_reader.CheckDataType(DBUS_TYPE_BYTE))
+    return false;
+  int int_length = 0;
+  dbus_message_iter_get_fixed_array(&array_reader.raw_message_iter_,
+                                    bytes,
+                                    &int_length);
+  *length = static_cast<size_t>(int_length);
+  return true;
+}
+
+bool MessageReader::PopArrayOfDoubles(const double** doubles, size_t* length) {
+  MessageReader array_reader(message_);
+  if (!PopArray(&array_reader))
+    return false;
+  if (!array_reader.HasMoreData()) {
+    *length = 0;
+    *doubles = nullptr;
+    return true;
+  }
+  if (!array_reader.CheckDataType(DBUS_TYPE_DOUBLE))
+    return false;
+  int int_length = 0;
+  dbus_message_iter_get_fixed_array(&array_reader.raw_message_iter_,
+                                    doubles,
+                                    &int_length);
+  *length = static_cast<size_t>(int_length);
+  return true;
+}
+
+bool MessageReader::PopArrayOfStrings(
+    std::vector<std::string> *strings) {
+  strings->clear();
+  MessageReader array_reader(message_);
+  if (!PopArray(&array_reader))
+    return false;
+  while (array_reader.HasMoreData()) {
+    std::string string;
+    if (!array_reader.PopString(&string))
+      return false;
+    strings->push_back(string);
+  }
+  return true;
+}
+
+bool MessageReader::PopArrayOfObjectPaths(
+    std::vector<ObjectPath> *object_paths) {
+  object_paths->clear();
+  MessageReader array_reader(message_);
+  if (!PopArray(&array_reader))
+    return false;
+  while (array_reader.HasMoreData()) {
+    ObjectPath object_path;
+    if (!array_reader.PopObjectPath(&object_path))
+      return false;
+    object_paths->push_back(object_path);
+  }
+  return true;
+}
+
+bool MessageReader::PopVariantOfByte(uint8_t* value) {
+  return PopVariantOfBasic(DBUS_TYPE_BYTE, value);
+}
+
+bool MessageReader::PopVariantOfBool(bool* value) {
+  // See the comment at MessageReader::PopBool().
+  dbus_bool_t dbus_value = FALSE;
+  const bool success = PopVariantOfBasic(DBUS_TYPE_BOOLEAN, &dbus_value);
+  *value = static_cast<bool>(dbus_value);
+  return success;
+}
+
+bool MessageReader::PopVariantOfInt16(int16_t* value) {
+  return PopVariantOfBasic(DBUS_TYPE_INT16, value);
+}
+
+bool MessageReader::PopVariantOfUint16(uint16_t* value) {
+  return PopVariantOfBasic(DBUS_TYPE_UINT16, value);
+}
+
+bool MessageReader::PopVariantOfInt32(int32_t* value) {
+  return PopVariantOfBasic(DBUS_TYPE_INT32, value);
+}
+
+bool MessageReader::PopVariantOfUint32(uint32_t* value) {
+  return PopVariantOfBasic(DBUS_TYPE_UINT32, value);
+}
+
+bool MessageReader::PopVariantOfInt64(int64_t* value) {
+  return PopVariantOfBasic(DBUS_TYPE_INT64, value);
+}
+
+bool MessageReader::PopVariantOfUint64(uint64_t* value) {
+  return PopVariantOfBasic(DBUS_TYPE_UINT64, value);
+}
+
+bool MessageReader::PopVariantOfDouble(double* value) {
+  return PopVariantOfBasic(DBUS_TYPE_DOUBLE, value);
+}
+
+bool MessageReader::PopVariantOfString(std::string* value) {
+  char* tmp_value = NULL;
+  const bool success = PopVariantOfBasic(DBUS_TYPE_STRING, &tmp_value);
+  if (success)
+    value->assign(tmp_value);
+  return success;
+}
+
+bool MessageReader::PopVariantOfObjectPath(ObjectPath* value) {
+  char* tmp_value = NULL;
+  const bool success = PopVariantOfBasic(DBUS_TYPE_OBJECT_PATH, &tmp_value);
+  if (success)
+    *value = ObjectPath(tmp_value);
+  return success;
+}
+
+Message::DataType MessageReader::GetDataType() {
+  const int dbus_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
+  return static_cast<Message::DataType>(dbus_type);
+}
+
+std::string MessageReader::GetDataSignature() {
+  std::string signature;
+  char* raw_signature = dbus_message_iter_get_signature(&raw_message_iter_);
+  if (raw_signature) {
+    signature = raw_signature;
+    dbus_free(raw_signature);
+  }
+  return signature;
+}
+
+bool MessageReader::CheckDataType(int dbus_type) {
+  const int actual_type = dbus_message_iter_get_arg_type(&raw_message_iter_);
+  if (actual_type != dbus_type) {
+    VLOG(1) << "Type " << dbus_type  << " is expected but got "
+            << actual_type;
+    return false;
+  }
+  return true;
+}
+
+bool MessageReader::PopBasic(int dbus_type, void* value) {
+  if (!CheckDataType(dbus_type))
+    return false;
+  // dbus_message_iter_get_basic() here should always work, as we have
+  // already checked the next item's data type in CheckDataType(). Note
+  // that dbus_message_iter_get_basic() is a void function.
+  dbus_message_iter_get_basic(&raw_message_iter_, value);
+  DCHECK(value);
+  dbus_message_iter_next(&raw_message_iter_);
+  return true;
+}
+
+bool MessageReader::PopContainer(int dbus_type, MessageReader* sub_reader) {
+  DCHECK_NE(this, sub_reader);
+
+  if (!CheckDataType(dbus_type))
+    return false;
+  dbus_message_iter_recurse(&raw_message_iter_,
+                            &sub_reader->raw_message_iter_);
+  dbus_message_iter_next(&raw_message_iter_);
+  return true;
+}
+
+bool MessageReader::PopVariantOfBasic(int dbus_type, void* value) {
+  MessageReader variant_reader(message_);
+  if (!PopVariant(&variant_reader))
+    return false;
+  return variant_reader.PopBasic(dbus_type, value);
+}
+
+bool MessageReader::PopFileDescriptor(FileDescriptor* value) {
+  CHECK(IsDBusTypeUnixFdSupported());
+
+  int fd = -1;
+  const bool success = PopBasic(DBUS_TYPE_UNIX_FD, &fd);
+  if (!success)
+    return false;
+
+  value->PutValue(fd);
+  // NB: the caller must check validity before using the value
+  return true;
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/message.h b/libchrome/dbus/message.h
new file mode 100644
index 0000000..e7b6be0
--- /dev/null
+++ b/libchrome/dbus/message.h
@@ -0,0 +1,487 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_MESSAGE_H_
+#define DBUS_MESSAGE_H_
+
+#include <dbus/dbus.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "dbus/dbus_export.h"
+#include "dbus/file_descriptor.h"
+#include "dbus/object_path.h"
+
+namespace google {
+namespace protobuf {
+
+class MessageLite;
+
+}  // namespace protobuf
+}  // namespace google
+
+
+namespace dbus {
+
+class MessageWriter;
+class MessageReader;
+
+// DBUS_TYPE_UNIX_FD was added in D-Bus version 1.4
+#if !defined(DBUS_TYPE_UNIX_FD)
+#define DBUS_TYPE_UNIX_FD      ((int) 'h')
+#endif
+
+// Returns true if Unix FD passing is supported in libdbus.
+// The check is done runtime rather than compile time as the libdbus
+// version used at runtime may be different from the one used at compile time.
+CHROME_DBUS_EXPORT bool IsDBusTypeUnixFdSupported();
+
+// Message is the base class of D-Bus message types. Client code must use
+// sub classes such as MethodCall and Response instead.
+//
+// The class name Message is very generic, but there should be no problem
+// as the class is inside 'dbus' namespace. We chose to name this way, as
+// libdbus defines lots of types starting with DBus, such as
+// DBusMessage. We should avoid confusion and conflict with these types.
+class CHROME_DBUS_EXPORT Message {
+ public:
+  // The message type used in D-Bus.  Redefined here so client code
+  // doesn't need to use raw D-Bus macros. DBUS_MESSAGE_TYPE_INVALID
+  // etc. are #define macros. Having an enum type here makes code a bit
+  // more type-safe.
+  enum MessageType {
+    MESSAGE_INVALID = DBUS_MESSAGE_TYPE_INVALID,
+    MESSAGE_METHOD_CALL = DBUS_MESSAGE_TYPE_METHOD_CALL,
+    MESSAGE_METHOD_RETURN = DBUS_MESSAGE_TYPE_METHOD_RETURN,
+    MESSAGE_SIGNAL = DBUS_MESSAGE_TYPE_SIGNAL,
+    MESSAGE_ERROR = DBUS_MESSAGE_TYPE_ERROR,
+ };
+
+  // The data type used in the D-Bus type system.  See the comment at
+  // MessageType for why we are redefining data types here.
+  enum DataType {
+    INVALID_DATA = DBUS_TYPE_INVALID,
+    BYTE = DBUS_TYPE_BYTE,
+    BOOL = DBUS_TYPE_BOOLEAN,
+    INT16 = DBUS_TYPE_INT16,
+    UINT16 = DBUS_TYPE_UINT16,
+    INT32 = DBUS_TYPE_INT32,
+    UINT32 = DBUS_TYPE_UINT32,
+    INT64 = DBUS_TYPE_INT64,
+    UINT64 = DBUS_TYPE_UINT64,
+    DOUBLE = DBUS_TYPE_DOUBLE,
+    STRING = DBUS_TYPE_STRING,
+    OBJECT_PATH = DBUS_TYPE_OBJECT_PATH,
+    ARRAY = DBUS_TYPE_ARRAY,
+    STRUCT = DBUS_TYPE_STRUCT,
+    DICT_ENTRY = DBUS_TYPE_DICT_ENTRY,
+    VARIANT = DBUS_TYPE_VARIANT,
+    UNIX_FD = DBUS_TYPE_UNIX_FD,
+  };
+
+  // Returns the type of the message. Returns MESSAGE_INVALID if
+  // raw_message_ is NULL.
+  MessageType GetMessageType();
+
+  // Returns the type of the message as string like "MESSAGE_METHOD_CALL"
+  // for instance.
+  std::string GetMessageTypeAsString();
+
+  DBusMessage* raw_message() { return raw_message_; }
+
+  // Sets the destination, the path, the interface, the member, etc.
+  bool SetDestination(const std::string& destination);
+  bool SetPath(const ObjectPath& path);
+  bool SetInterface(const std::string& interface);
+  bool SetMember(const std::string& member);
+  bool SetErrorName(const std::string& error_name);
+  bool SetSender(const std::string& sender);
+  void SetSerial(uint32_t serial);
+  void SetReplySerial(uint32_t reply_serial);
+  // SetSignature() does not exist as we cannot do it.
+
+  // Gets the destination, the path, the interface, the member, etc.
+  // If not set, an empty string is returned.
+  std::string GetDestination();
+  ObjectPath GetPath();
+  std::string GetInterface();
+  std::string GetMember();
+  std::string GetErrorName();
+  std::string GetSender();
+  std::string GetSignature();
+  // Gets the serial and reply serial numbers. Returns 0 if not set.
+  uint32_t GetSerial();
+  uint32_t GetReplySerial();
+
+  // Returns the string representation of this message. Useful for
+  // debugging. The output is truncated as needed (ex. strings are truncated
+  // if longer than a certain limit defined in the .cc file).
+  std::string ToString();
+
+ protected:
+  // This class cannot be instantiated. Use sub classes instead.
+  Message();
+  virtual ~Message();
+
+  // Initializes the message with the given raw message.
+  void Init(DBusMessage* raw_message);
+
+ private:
+  // Helper function used in ToString().
+  std::string ToStringInternal(const std::string& indent,
+                               MessageReader* reader);
+
+  DBusMessage* raw_message_;
+  DISALLOW_COPY_AND_ASSIGN(Message);
+};
+
+// MessageCall is a type of message used for calling a method via D-Bus.
+class CHROME_DBUS_EXPORT MethodCall : public Message {
+ public:
+  // Creates a method call message for the specified interface name and
+  // the method name.
+  //
+  // For instance, to call "Get" method of DBUS_INTERFACE_INTROSPECTABLE
+  // interface ("org.freedesktop.DBus.Introspectable"), create a method
+  // call like this:
+  //
+  //   MethodCall method_call(DBUS_INTERFACE_INTROSPECTABLE, "Get");
+  //
+  // The constructor creates the internal raw message.
+  MethodCall(const std::string& interface_name,
+             const std::string& method_name);
+
+  // Returns a newly created MethodCall from the given raw message of the
+  // type DBUS_MESSAGE_TYPE_METHOD_CALL. The caller must delete the
+  // returned object. Takes the ownership of |raw_message|.
+  static MethodCall* FromRawMessage(DBusMessage* raw_message);
+
+ private:
+  // Creates a method call message. The internal raw message is NULL.
+  // Only used internally.
+  MethodCall();
+
+  DISALLOW_COPY_AND_ASSIGN(MethodCall);
+};
+
+// Signal is a type of message used to send a signal.
+class CHROME_DBUS_EXPORT Signal : public Message {
+ public:
+  // Creates a signal message for the specified interface name and the
+  // method name.
+  //
+  // For instance, to send "PropertiesChanged" signal of
+  // DBUS_INTERFACE_INTROSPECTABLE interface
+  // ("org.freedesktop.DBus.Introspectable"), create a signal like this:
+  //
+  //   Signal signal(DBUS_INTERFACE_INTROSPECTABLE, "PropertiesChanged");
+  //
+  // The constructor creates the internal raw_message_.
+  Signal(const std::string& interface_name,
+         const std::string& method_name);
+
+  // Returns a newly created SIGNAL from the given raw message of the type
+  // DBUS_MESSAGE_TYPE_SIGNAL. The caller must delete the returned
+  // object. Takes the ownership of |raw_message|.
+  static Signal* FromRawMessage(DBusMessage* raw_message);
+
+ private:
+  // Creates a signal message. The internal raw message is NULL.
+  // Only used internally.
+  Signal();
+
+  DISALLOW_COPY_AND_ASSIGN(Signal);
+};
+
+// Response is a type of message used for receiving a response from a
+// method via D-Bus.
+class CHROME_DBUS_EXPORT Response : public Message {
+ public:
+  // Returns a newly created Response from the given raw message of the
+  // type DBUS_MESSAGE_TYPE_METHOD_RETURN. Takes the ownership of |raw_message|.
+  static std::unique_ptr<Response> FromRawMessage(DBusMessage* raw_message);
+
+  // Returns a newly created Response from the given method call.
+  // Used for implementing exported methods. Does NOT take the ownership of
+  // |method_call|.
+  static std::unique_ptr<Response> FromMethodCall(MethodCall* method_call);
+
+  // Returns a newly created Response with an empty payload.
+  // Useful for testing.
+  static std::unique_ptr<Response> CreateEmpty();
+
+ protected:
+  // Creates a Response message. The internal raw message is NULL.
+  Response();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Response);
+};
+
+// ErrorResponse is a type of message used to return an error to the
+// caller of a method.
+class CHROME_DBUS_EXPORT ErrorResponse: public Response {
+ public:
+  // Returns a newly created Response from the given raw message of the
+  // type DBUS_MESSAGE_TYPE_METHOD_RETURN. Takes the ownership of |raw_message|.
+  static std::unique_ptr<ErrorResponse> FromRawMessage(
+      DBusMessage* raw_message);
+
+  // Returns a newly created ErrorResponse from the given method call, the
+  // error name, and the error message.  The error name looks like
+  // "org.freedesktop.DBus.Error.Failed". Used for returning an error to a
+  // failed method call. Does NOT take the ownership of |method_call|.
+  static std::unique_ptr<ErrorResponse> FromMethodCall(
+      MethodCall* method_call,
+      const std::string& error_name,
+      const std::string& error_message);
+
+ private:
+  // Creates an ErrorResponse message. The internal raw message is NULL.
+  ErrorResponse();
+
+  DISALLOW_COPY_AND_ASSIGN(ErrorResponse);
+};
+
+// MessageWriter is used to write outgoing messages for calling methods
+// and sending signals.
+//
+// The main design goal of MessageReader and MessageWriter classes is to
+// provide a type safe API. In the past, there was a Chrome OS blocker
+// bug, that took days to fix, that would have been prevented if the API
+// was type-safe.
+//
+// For instance, instead of doing something like:
+//
+//   // We shouldn't add '&' to str here, but it compiles with '&' added.
+//   dbus_g_proxy_call(..., G_TYPE_STRING, str, G_TYPE_INVALID, ...)
+//
+// We want to do something like:
+//
+//   writer.AppendString(str);
+//
+class CHROME_DBUS_EXPORT MessageWriter {
+ public:
+  // Data added with Append* will be written to |message|, which may be NULL
+  // to create a sub-writer for passing to OpenArray, etc.
+  explicit MessageWriter(Message* message);
+  ~MessageWriter();
+
+  // Appends a byte to the message.
+  void AppendByte(uint8_t value);
+  void AppendBool(bool value);
+  void AppendInt16(int16_t value);
+  void AppendUint16(uint16_t value);
+  void AppendInt32(int32_t value);
+  void AppendUint32(uint32_t value);
+  void AppendInt64(int64_t value);
+  void AppendUint64(uint64_t value);
+  void AppendDouble(double value);
+  void AppendString(const std::string& value);
+  void AppendObjectPath(const ObjectPath& value);
+  void AppendFileDescriptor(const FileDescriptor& value);
+
+  // Opens an array. The array contents can be added to the array with
+  // |sub_writer|. The client code must close the array with
+  // CloseContainer(), once all contents are added.
+  //
+  // |signature| parameter is used to supply the D-Bus type signature of
+  // the array contents. For instance, if you want an array of strings,
+  // then you pass "s" as the signature.
+  //
+  // See the spec for details about the type signatures.
+  // http://dbus.freedesktop.org/doc/dbus-specification.html
+  // #message-protocol-signatures
+  //
+  void OpenArray(const std::string& signature, MessageWriter* sub_writer);
+  // Do the same for a variant.
+  void OpenVariant(const std::string& signature, MessageWriter* sub_writer);
+  // Do the same for Struct and dict entry. They don't need the signature.
+  void OpenStruct(MessageWriter* sub_writer);
+  void OpenDictEntry(MessageWriter* sub_writer);
+
+  // Close the container for a array/variant/struct/dict entry.
+  void CloseContainer(MessageWriter* sub_writer);
+
+  // Appends the array of bytes. Arrays of bytes are often used for
+  // exchanging binary blobs hence it's worth having a specialized
+  // function.
+  void AppendArrayOfBytes(const uint8_t* values, size_t length);
+
+  // Appends the array of doubles. Used for audio mixer matrix doubles.
+  void AppendArrayOfDoubles(const double* values, size_t length);
+
+  // Appends the array of strings. Arrays of strings are often used for
+  // exchanging lists of names hence it's worth having a specialized
+  // function.
+  void AppendArrayOfStrings(const std::vector<std::string>& strings);
+
+  // Appends the array of object paths. Arrays of object paths are often
+  // used when exchanging object paths, hence it's worth having a
+  // specialized function.
+  void AppendArrayOfObjectPaths(const std::vector<ObjectPath>& object_paths);
+
+  // Appends the byte wrapped in a variant data container. Variants are
+  // widely used in D-Bus services so it's worth having a specialized
+  // function. For instance, The third parameter of
+  // "org.freedesktop.DBus.Properties.Set" is a variant.
+  void AppendVariantOfByte(uint8_t value);
+  void AppendVariantOfBool(bool value);
+  void AppendVariantOfInt16(int16_t value);
+  void AppendVariantOfUint16(uint16_t value);
+  void AppendVariantOfInt32(int32_t value);
+  void AppendVariantOfUint32(uint32_t value);
+  void AppendVariantOfInt64(int64_t value);
+  void AppendVariantOfUint64(uint64_t value);
+  void AppendVariantOfDouble(double value);
+  void AppendVariantOfString(const std::string& value);
+  void AppendVariantOfObjectPath(const ObjectPath& value);
+
+ private:
+  // Helper function used to implement AppendByte etc.
+  void AppendBasic(int dbus_type, const void* value);
+
+  // Helper function used to implement AppendVariantOfByte() etc.
+  void AppendVariantOfBasic(int dbus_type, const void* value);
+
+  Message* message_;
+  DBusMessageIter raw_message_iter_;
+  bool container_is_open_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageWriter);
+};
+
+// MessageReader is used to read incoming messages such as responses for
+// method calls.
+//
+// MessageReader manages an internal iterator to read data. All functions
+// starting with Pop advance the iterator on success.
+class CHROME_DBUS_EXPORT MessageReader {
+ public:
+  // The data will be read from the given |message|, which may be NULL to
+  // create a sub-reader for passing to PopArray, etc.
+  explicit MessageReader(Message* message);
+  ~MessageReader();
+
+  // Returns true if the reader has more data to read. The function is
+  // used to iterate contents in a container like:
+  //
+  //   while (reader.HasMoreData())
+  //     reader.PopString(&value);
+  bool HasMoreData();
+
+  // Gets the byte at the current iterator position.
+  // Returns true and advances the iterator on success.
+  // Returns false if the data type is not a byte.
+  bool PopByte(uint8_t* value);
+  bool PopBool(bool* value);
+  bool PopInt16(int16_t* value);
+  bool PopUint16(uint16_t* value);
+  bool PopInt32(int32_t* value);
+  bool PopUint32(uint32_t* value);
+  bool PopInt64(int64_t* value);
+  bool PopUint64(uint64_t* value);
+  bool PopDouble(double* value);
+  bool PopString(std::string* value);
+  bool PopObjectPath(ObjectPath* value);
+  bool PopFileDescriptor(FileDescriptor* value);
+
+  // Sets up the given message reader to read an array at the current
+  // iterator position.
+  // Returns true and advances the iterator on success.
+  // Returns false if the data type is not an array
+  bool PopArray(MessageReader* sub_reader);
+  bool PopStruct(MessageReader* sub_reader);
+  bool PopDictEntry(MessageReader* sub_reader);
+  bool PopVariant(MessageReader* sub_reader);
+
+  // Gets the array of bytes at the current iterator position.
+  // Returns true and advances the iterator on success.
+  //
+  // Arrays of bytes are often used for exchanging binary blobs hence it's
+  // worth having a specialized function.
+  //
+  // Ownership of the memory pointed to by |bytes| remains with the
+  // MessageReader; |bytes| must be copied if the contents will be referenced
+  // after the MessageReader is destroyed.
+  bool PopArrayOfBytes(const uint8_t** bytes, size_t* length);
+
+  // Gets the array of doubles at the current iterator position.
+  bool PopArrayOfDoubles(const double** doubles, size_t* length);
+
+  // Gets the array of strings at the current iterator position. |strings| is
+  // cleared before being modified. Returns true and advances the iterator on
+  // success.
+  //
+  // Arrays of strings are often used to communicate with D-Bus
+  // services like KWallet, hence it's worth having a specialized
+  // function.
+  bool PopArrayOfStrings(std::vector<std::string>* strings);
+
+  // Gets the array of object paths at the current iterator position.
+  // |object_paths| is cleared before being modified. Returns true and advances
+  // the iterator on success.
+  //
+  // Arrays of object paths are often used to communicate with D-Bus
+  // services like NetworkManager, hence it's worth having a specialized
+  // function.
+  bool PopArrayOfObjectPaths(std::vector<ObjectPath>* object_paths);
+
+  // Gets the byte from the variant data container at the current iterator
+  // position.
+  // Returns true and advances the iterator on success.
+  //
+  // Variants are widely used in D-Bus services so it's worth having a
+  // specialized function. For instance, The return value type of
+  // "org.freedesktop.DBus.Properties.Get" is a variant.
+  bool PopVariantOfByte(uint8_t* value);
+  bool PopVariantOfBool(bool* value);
+  bool PopVariantOfInt16(int16_t* value);
+  bool PopVariantOfUint16(uint16_t* value);
+  bool PopVariantOfInt32(int32_t* value);
+  bool PopVariantOfUint32(uint32_t* value);
+  bool PopVariantOfInt64(int64_t* value);
+  bool PopVariantOfUint64(uint64_t* value);
+  bool PopVariantOfDouble(double* value);
+  bool PopVariantOfString(std::string* value);
+  bool PopVariantOfObjectPath(ObjectPath* value);
+
+  // Get the data type of the value at the current iterator
+  // position. INVALID_DATA will be returned if the iterator points to the
+  // end of the message.
+  Message::DataType GetDataType();
+
+  // Get the DBus signature of the value at the current iterator position.
+  // An empty string will be returned if the iterator points to the end of
+  // the message.
+  std::string GetDataSignature();
+
+ private:
+  // Returns true if the data type at the current iterator position
+  // matches the given D-Bus type, such as DBUS_TYPE_BYTE.
+  bool CheckDataType(int dbus_type);
+
+  // Helper function used to implement PopByte() etc.
+  bool PopBasic(int dbus_type, void *value);
+
+  // Helper function used to implement PopArray() etc.
+  bool PopContainer(int dbus_type, MessageReader* sub_reader);
+
+  // Helper function used to implement PopVariantOfByte() etc.
+  bool PopVariantOfBasic(int dbus_type, void* value);
+
+  Message* message_;
+  DBusMessageIter raw_message_iter_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageReader);
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_MESSAGE_H_
diff --git a/libchrome/dbus/mock_bus.cc b/libchrome/dbus/mock_bus.cc
new file mode 100644
index 0000000..9e76454
--- /dev/null
+++ b/libchrome/dbus/mock_bus.cc
@@ -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.
+
+#include "dbus/mock_bus.h"
+
+#include "base/location.h"
+
+namespace dbus {
+
+MockBus::MockBus(const Bus::Options& options) : Bus(options) {
+}
+
+MockBus::~MockBus() {
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/mock_bus.h b/libchrome/dbus/mock_bus.h
new file mode 100644
index 0000000..b50f230
--- /dev/null
+++ b/libchrome/dbus/mock_bus.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 DBUS_MOCK_BUS_H_
+#define DBUS_MOCK_BUS_H_
+
+#include <stdint.h>
+
+#include "dbus/bus.h"
+#include "dbus/object_path.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dbus {
+
+// Mock for Bus class. Along with MockObjectProxy and MockExportedObject,
+// the mock classes can be used to write unit tests without issuing real
+// D-Bus calls.
+class MockBus : public Bus {
+ public:
+  MockBus(const Bus::Options& options);
+
+  MOCK_METHOD2(GetObjectProxy, ObjectProxy*(const std::string& service_name,
+                                            const ObjectPath& object_path));
+  MOCK_METHOD3(GetObjectProxyWithOptions,
+               ObjectProxy*(const std::string& service_name,
+                            const ObjectPath& object_path,
+                            int options));
+  MOCK_METHOD3(RemoveObjectProxy, bool(
+      const std::string& service_name,
+      const ObjectPath& object_path,
+      const base::Closure& callback));
+  MOCK_METHOD4(RemoveObjectProxyWithOptions, bool(
+      const std::string& service_name,
+      const ObjectPath& object_path,
+      int options,
+      const base::Closure& callback));
+  MOCK_METHOD1(GetExportedObject, ExportedObject*(
+      const ObjectPath& object_path));
+  MOCK_METHOD2(GetObjectManager, ObjectManager*(const std::string&,
+                                                const ObjectPath&));
+  MOCK_METHOD0(ShutdownAndBlock, void());
+  MOCK_METHOD0(ShutdownOnDBusThreadAndBlock, void());
+  MOCK_METHOD0(Connect, bool());
+  MOCK_METHOD3(RequestOwnership, void(
+      const std::string& service_name,
+      ServiceOwnershipOptions options,
+      OnOwnershipCallback on_ownership_callback));
+  MOCK_METHOD2(RequestOwnershipAndBlock, bool(const std::string& service_name,
+                                              ServiceOwnershipOptions options));
+  MOCK_METHOD1(ReleaseOwnership, bool(const std::string& service_name));
+  MOCK_METHOD0(SetUpAsyncOperations, bool());
+  MOCK_METHOD3(SendWithReplyAndBlock, DBusMessage*(DBusMessage* request,
+                                                   int timeout_ms,
+                                                   DBusError* error));
+  MOCK_METHOD3(SendWithReply, void(DBusMessage* request,
+                                   DBusPendingCall** pending_call,
+                                   int timeout_ms));
+  MOCK_METHOD2(Send, void(DBusMessage* request, uint32_t* serial));
+  MOCK_METHOD2(AddFilter, void(DBusHandleMessageFunction handle_message,
+                               void* user_data));
+  MOCK_METHOD2(RemoveFilter, void(DBusHandleMessageFunction handle_message,
+                                  void* user_data));
+  MOCK_METHOD2(AddMatch, void(const std::string& match_rule,
+                              DBusError* error));
+  MOCK_METHOD2(RemoveMatch, bool(const std::string& match_rule,
+                                 DBusError* error));
+  MOCK_METHOD4(TryRegisterObjectPath, bool(const ObjectPath& object_path,
+                                           const DBusObjectPathVTable* vtable,
+                                           void* user_data,
+                                           DBusError* error));
+  MOCK_METHOD1(UnregisterObjectPath, void(const ObjectPath& object_path));
+  MOCK_METHOD0(GetDBusTaskRunner, base::TaskRunner*());
+  MOCK_METHOD0(GetOriginTaskRunner, base::TaskRunner*());
+  MOCK_METHOD0(HasDBusThread, bool());
+  MOCK_METHOD0(AssertOnOriginThread, void());
+  MOCK_METHOD0(AssertOnDBusThread, void());
+
+ protected:
+  virtual ~MockBus();
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_MOCK_BUS_H_
diff --git a/libchrome/dbus/mock_exported_object.cc b/libchrome/dbus/mock_exported_object.cc
new file mode 100644
index 0000000..ff507dd
--- /dev/null
+++ b/libchrome/dbus/mock_exported_object.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 "dbus/mock_exported_object.h"
+
+namespace dbus {
+
+MockExportedObject::MockExportedObject(Bus* bus,
+                                       const ObjectPath& object_path)
+    : ExportedObject(bus, object_path) {
+}
+
+MockExportedObject::~MockExportedObject() {
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/mock_exported_object.h b/libchrome/dbus/mock_exported_object.h
new file mode 100644
index 0000000..80ca951
--- /dev/null
+++ b/libchrome/dbus/mock_exported_object.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 DBUS_MOCK_EXPORTED_OBJECT_H_
+#define DBUS_MOCK_EXPORTED_OBJECT_H_
+
+#include <string>
+
+#include "dbus/exported_object.h"
+#include "dbus/object_path.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dbus {
+
+// Mock for ExportedObject.
+class MockExportedObject : public ExportedObject {
+ public:
+  MockExportedObject(Bus* bus,
+                     const ObjectPath& object_path);
+
+  MOCK_METHOD3(ExportMethodAndBlock,
+               bool(const std::string& interface_name,
+                    const std::string& method_name,
+                    MethodCallCallback method_call_callback));
+  MOCK_METHOD4(ExportMethod,
+               void(const std::string& interface_name,
+                    const std::string& method_name,
+                    MethodCallCallback method_call_callback,
+                    OnExportedCallback on_exported_callback));
+  MOCK_METHOD1(SendSignal, void(Signal* signal));
+  MOCK_METHOD0(Unregister, void());
+
+ protected:
+  virtual ~MockExportedObject();
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_MOCK_EXPORTED_OBJECT_H_
diff --git a/libchrome/dbus/mock_object_manager.cc b/libchrome/dbus/mock_object_manager.cc
new file mode 100644
index 0000000..dcba78e
--- /dev/null
+++ b/libchrome/dbus/mock_object_manager.cc
@@ -0,0 +1,18 @@
+// 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 "dbus/mock_object_manager.h"
+
+namespace dbus {
+
+MockObjectManager::MockObjectManager(Bus* bus,
+                                     const std::string& service_name,
+                                     const ObjectPath& object_path)
+    : ObjectManager(bus, service_name, object_path) {
+}
+
+MockObjectManager::~MockObjectManager() {
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/mock_object_manager.h b/libchrome/dbus/mock_object_manager.h
new file mode 100644
index 0000000..e4c76ba
--- /dev/null
+++ b/libchrome/dbus/mock_object_manager.h
@@ -0,0 +1,42 @@
+// 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 DBUS_MOCK_OBJECT_MANAGER_H_
+#define DBUS_MOCK_OBJECT_MANAGER_H_
+
+#include <string>
+
+#include "dbus/message.h"
+#include "dbus/object_manager.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dbus {
+
+// Mock for ObjectManager.
+class MockObjectManager : public ObjectManager {
+ public:
+  MockObjectManager(Bus* bus,
+                    const std::string& service_name,
+                    const ObjectPath& object_path);
+
+  MOCK_METHOD2(RegisterInterface, void(const std::string&,
+                                       Interface*));
+  MOCK_METHOD1(UnregisterInterface, void(const std::string&));
+  MOCK_METHOD0(GetObjects, std::vector<ObjectPath>());
+  MOCK_METHOD1(GetObjectsWithInterface,
+               std::vector<ObjectPath>(const std::string&));
+  MOCK_METHOD1(GetObjectProxy, ObjectProxy*(const ObjectPath&));
+  MOCK_METHOD2(GetProperties, PropertySet*(const ObjectPath&,
+                                           const std::string&));
+  MOCK_METHOD0(GetManagedObjects, void());
+
+ protected:
+  virtual ~MockObjectManager();
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_MOCK_OBJECT_MANAGER_H_
diff --git a/libchrome/dbus/mock_object_proxy.cc b/libchrome/dbus/mock_object_proxy.cc
new file mode 100644
index 0000000..7e26f01
--- /dev/null
+++ b/libchrome/dbus/mock_object_proxy.cc
@@ -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.
+
+#include "dbus/mock_object_proxy.h"
+
+namespace dbus {
+
+MockObjectProxy::MockObjectProxy(Bus* bus,
+                                 const std::string& service_name,
+                                 const ObjectPath& object_path)
+    : ObjectProxy(bus, service_name, object_path, DEFAULT_OPTIONS) {
+}
+
+MockObjectProxy::~MockObjectProxy() {
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/mock_object_proxy.h b/libchrome/dbus/mock_object_proxy.h
new file mode 100644
index 0000000..f27f6f6
--- /dev/null
+++ b/libchrome/dbus/mock_object_proxy.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 DBUS_MOCK_OBJECT_PROXY_H_
+#define DBUS_MOCK_OBJECT_PROXY_H_
+
+#include <string>
+
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dbus {
+
+// Mock for ObjectProxy.
+class MockObjectProxy : public ObjectProxy {
+ public:
+  MockObjectProxy(Bus* bus,
+                  const std::string& service_name,
+                  const ObjectPath& object_path);
+
+  // GMock doesn't support the return type of std::unique_ptr<> because
+  // std::unique_ptr is uncopyable. This is a workaround which defines
+  // |MockCallMethodAndBlock| as a mock method and makes
+  // |CallMethodAndBlock| call the mocked method.  Use |MockCallMethodAndBlock|
+  // for setting/testing expectations.
+  MOCK_METHOD3(MockCallMethodAndBlockWithErrorDetails,
+               Response*(MethodCall* method_call,
+                         int timeout_ms,
+                         ScopedDBusError* error));
+  std::unique_ptr<Response> CallMethodAndBlockWithErrorDetails(
+      MethodCall* method_call,
+      int timeout_ms,
+      ScopedDBusError* error) override {
+    return std::unique_ptr<Response>(
+        MockCallMethodAndBlockWithErrorDetails(method_call, timeout_ms, error));
+  }
+  MOCK_METHOD2(MockCallMethodAndBlock, Response*(MethodCall* method_call,
+                                                 int timeout_ms));
+  std::unique_ptr<Response> CallMethodAndBlock(MethodCall* method_call,
+                                               int timeout_ms) override {
+    return std::unique_ptr<Response>(
+        MockCallMethodAndBlock(method_call, timeout_ms));
+  }
+  MOCK_METHOD3(CallMethod, void(MethodCall* method_call,
+                                int timeout_ms,
+                                ResponseCallback callback));
+  MOCK_METHOD4(CallMethodWithErrorCallback, void(MethodCall* method_call,
+                                                 int timeout_ms,
+                                                 ResponseCallback callback,
+                                                 ErrorCallback error_callback));
+  MOCK_METHOD4(ConnectToSignal,
+               void(const std::string& interface_name,
+                    const std::string& signal_name,
+                    SignalCallback signal_callback,
+                    OnConnectedCallback on_connected_callback));
+  MOCK_METHOD0(Detach, void());
+
+ protected:
+  ~MockObjectProxy() override;
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_MOCK_OBJECT_PROXY_H_
diff --git a/libchrome/dbus/object_manager.cc b/libchrome/dbus/object_manager.cc
new file mode 100644
index 0000000..178bb5f
--- /dev/null
+++ b/libchrome/dbus/object_manager.cc
@@ -0,0 +1,536 @@
+// 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 "dbus/object_manager.h"
+
+#include <stddef.h>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "base/task_runner_util.h"
+#include "dbus/bus.h"
+#include "dbus/dbus_statistics.h"
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+#include "dbus/property.h"
+#include "dbus/scoped_dbus_error.h"
+#include "dbus/util.h"
+
+namespace dbus {
+
+ObjectManager::Object::Object()
+  : object_proxy(NULL) {
+}
+
+ObjectManager::Object::~Object() {
+}
+
+ObjectManager::ObjectManager(Bus* bus,
+                             const std::string& service_name,
+                             const ObjectPath& object_path)
+    : bus_(bus),
+      service_name_(service_name),
+      object_path_(object_path),
+      setup_success_(false),
+      cleanup_called_(false),
+      weak_ptr_factory_(this) {
+  DVLOG(1) << "Creating ObjectManager for " << service_name_
+           << " " << object_path_.value();
+  DCHECK(bus_);
+  bus_->AssertOnOriginThread();
+  object_proxy_ = bus_->GetObjectProxy(service_name_, object_path_);
+  object_proxy_->SetNameOwnerChangedCallback(
+      base::Bind(&ObjectManager::NameOwnerChanged,
+                 weak_ptr_factory_.GetWeakPtr()));
+
+  // Set up a match rule and a filter function to handle PropertiesChanged
+  // signals from the service. This is important to avoid any race conditions
+  // that might cause us to miss PropertiesChanged signals once all objects are
+  // initialized via GetManagedObjects.
+  base::PostTaskAndReplyWithResult(
+      bus_->GetDBusTaskRunner(),
+      FROM_HERE,
+      base::Bind(&ObjectManager::SetupMatchRuleAndFilter, this),
+      base::Bind(&ObjectManager::OnSetupMatchRuleAndFilterComplete, this));
+}
+
+ObjectManager::~ObjectManager() {
+  // Clean up Object structures
+  for (ObjectMap::iterator iter = object_map_.begin();
+       iter != object_map_.end(); ++iter) {
+    Object* object = iter->second;
+
+    for (Object::PropertiesMap::iterator piter = object->properties_map.begin();
+         piter != object->properties_map.end(); ++piter) {
+      PropertySet* properties = piter->second;
+      delete properties;
+    }
+
+    delete object;
+  }
+}
+
+void ObjectManager::RegisterInterface(const std::string& interface_name,
+                                      Interface* interface) {
+  interface_map_[interface_name] = interface;
+}
+
+void ObjectManager::UnregisterInterface(const std::string& interface_name) {
+  InterfaceMap::iterator iter = interface_map_.find(interface_name);
+  if (iter != interface_map_.end())
+    interface_map_.erase(iter);
+}
+
+std::vector<ObjectPath> ObjectManager::GetObjects() {
+  std::vector<ObjectPath> object_paths;
+
+  for (ObjectMap::iterator iter = object_map_.begin();
+       iter != object_map_.end(); ++iter)
+    object_paths.push_back(iter->first);
+
+  return object_paths;
+}
+
+std::vector<ObjectPath> ObjectManager::GetObjectsWithInterface(
+      const std::string& interface_name) {
+  std::vector<ObjectPath> object_paths;
+
+  for (ObjectMap::iterator oiter = object_map_.begin();
+       oiter != object_map_.end(); ++oiter) {
+    Object* object = oiter->second;
+
+    Object::PropertiesMap::iterator piter =
+        object->properties_map.find(interface_name);
+    if (piter != object->properties_map.end())
+      object_paths.push_back(oiter->first);
+  }
+
+  return object_paths;
+}
+
+ObjectProxy* ObjectManager::GetObjectProxy(const ObjectPath& object_path) {
+  ObjectMap::iterator iter = object_map_.find(object_path);
+  if (iter == object_map_.end())
+    return NULL;
+
+  Object* object = iter->second;
+  return object->object_proxy;
+}
+
+PropertySet* ObjectManager::GetProperties(const ObjectPath& object_path,
+                                          const std::string& interface_name) {
+  ObjectMap::iterator iter = object_map_.find(object_path);
+  if (iter == object_map_.end())
+    return NULL;
+
+  Object* object = iter->second;
+  Object::PropertiesMap::iterator piter =
+      object->properties_map.find(interface_name);
+  if (piter == object->properties_map.end())
+    return NULL;
+
+  return piter->second;
+}
+
+void ObjectManager::GetManagedObjects() {
+  MethodCall method_call(kObjectManagerInterface,
+                         kObjectManagerGetManagedObjects);
+
+  object_proxy_->CallMethod(
+      &method_call,
+      ObjectProxy::TIMEOUT_USE_DEFAULT,
+      base::Bind(&ObjectManager::OnGetManagedObjects,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ObjectManager::CleanUp() {
+  DCHECK(bus_);
+  bus_->AssertOnDBusThread();
+  DCHECK(!cleanup_called_);
+
+  cleanup_called_ = true;
+
+  if (!setup_success_)
+    return;
+
+  bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
+
+  ScopedDBusError error;
+  bus_->RemoveMatch(match_rule_, error.get());
+  if (error.is_set())
+    LOG(ERROR) << "Failed to remove match rule: " << match_rule_;
+
+  match_rule_.clear();
+}
+
+void ObjectManager::InitializeObjects() {
+  DCHECK(bus_);
+  DCHECK(object_proxy_);
+  DCHECK(setup_success_);
+
+  // |object_proxy_| is no longer valid if the Bus was shut down before this
+  // call. Don't initiate any other action from the origin thread.
+  if (cleanup_called_)
+    return;
+
+  object_proxy_->ConnectToSignal(
+      kObjectManagerInterface,
+      kObjectManagerInterfacesAdded,
+      base::Bind(&ObjectManager::InterfacesAddedReceived,
+                 weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&ObjectManager::InterfacesAddedConnected,
+                 weak_ptr_factory_.GetWeakPtr()));
+
+  object_proxy_->ConnectToSignal(
+      kObjectManagerInterface,
+      kObjectManagerInterfacesRemoved,
+      base::Bind(&ObjectManager::InterfacesRemovedReceived,
+                 weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&ObjectManager::InterfacesRemovedConnected,
+                 weak_ptr_factory_.GetWeakPtr()));
+
+  GetManagedObjects();
+}
+
+bool ObjectManager::SetupMatchRuleAndFilter() {
+  DCHECK(bus_);
+  DCHECK(!setup_success_);
+  bus_->AssertOnDBusThread();
+
+  if (cleanup_called_)
+    return false;
+
+  if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
+    return false;
+
+  service_name_owner_ =
+      bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
+
+  const std::string match_rule =
+      base::StringPrintf(
+          "type='signal', sender='%s', interface='%s', member='%s'",
+          service_name_.c_str(),
+          kPropertiesInterface,
+          kPropertiesChanged);
+
+  bus_->AddFilterFunction(&ObjectManager::HandleMessageThunk, this);
+
+  ScopedDBusError error;
+  bus_->AddMatch(match_rule, error.get());
+  if (error.is_set()) {
+    LOG(ERROR) << "ObjectManager failed to add match rule \"" << match_rule
+               << "\". Got " << error.name() << ": " << error.message();
+    bus_->RemoveFilterFunction(&ObjectManager::HandleMessageThunk, this);
+    return false;
+  }
+
+  match_rule_ = match_rule;
+  setup_success_ = true;
+
+  return true;
+}
+
+void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
+  LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
+                            << ": Failed to set up match rule.";
+  if (success)
+    InitializeObjects();
+}
+
+// static
+DBusHandlerResult ObjectManager::HandleMessageThunk(DBusConnection* connection,
+                                                    DBusMessage* raw_message,
+                                                    void* user_data) {
+  ObjectManager* self = reinterpret_cast<ObjectManager*>(user_data);
+  return self->HandleMessage(connection, raw_message);
+}
+
+DBusHandlerResult ObjectManager::HandleMessage(DBusConnection*,
+                                               DBusMessage* raw_message) {
+  DCHECK(bus_);
+  bus_->AssertOnDBusThread();
+
+  // Handle the message only if it is a signal.
+  // Note that the match rule in SetupMatchRuleAndFilter() is configured to
+  // only accept signals, but we check here just in case.
+  if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  // raw_message will be unrefed on exit of the function. Increment the
+  // reference so we can use it in Signal.
+  dbus_message_ref(raw_message);
+  std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
+
+  const std::string interface = signal->GetInterface();
+  const std::string member = signal->GetMember();
+
+  statistics::AddReceivedSignal(service_name_, interface, member);
+
+  // Handle the signal only if it is PropertiesChanged.
+  // Note that the match rule in SetupMatchRuleAndFilter() is configured to
+  // only accept PropertiesChanged signals, but we check here just in case.
+  const std::string absolute_signal_name =
+      GetAbsoluteMemberName(interface, member);
+  const std::string properties_changed_signal_name =
+      GetAbsoluteMemberName(kPropertiesInterface, kPropertiesChanged);
+  if (absolute_signal_name != properties_changed_signal_name)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  VLOG(1) << "Signal received: " << signal->ToString();
+
+  // Handle the signal only if it is from the service that the ObjectManager
+  // instance is interested in.
+  // Note that the match rule in SetupMatchRuleAndFilter() is configured to
+  // only accept messages from the service name of our interest. However, the
+  // service='...' filter does not work as intended. See crbug.com/507206#14
+  // and #15 for details, hence it's necessary to check the sender here.
+  std::string sender = signal->GetSender();
+  if (service_name_owner_ != sender)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  const ObjectPath path = signal->GetPath();
+
+  if (bus_->HasDBusThread()) {
+    // Post a task to run the method in the origin thread. Transfer ownership of
+    // |signal| to NotifyPropertiesChanged, which will handle the clean up.
+    Signal* released_signal = signal.release();
+    bus_->GetOriginTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ObjectManager::NotifyPropertiesChanged,
+                   this, path,
+                   released_signal));
+  } else {
+    // If the D-Bus thread is not used, just call the callback on the
+    // current thread. Transfer the ownership of |signal| to
+    // NotifyPropertiesChanged.
+    NotifyPropertiesChanged(path, signal.release());
+  }
+
+  // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
+  // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+void ObjectManager::NotifyPropertiesChanged(
+    const dbus::ObjectPath object_path,
+    Signal* signal) {
+  DCHECK(bus_);
+  bus_->AssertOnOriginThread();
+
+  NotifyPropertiesChangedHelper(object_path, signal);
+
+  // Delete the message on the D-Bus thread. See comments in HandleMessage.
+  bus_->GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&base::DeletePointer<Signal>, signal));
+}
+
+void ObjectManager::NotifyPropertiesChangedHelper(
+    const dbus::ObjectPath object_path,
+    Signal* signal) {
+  DCHECK(bus_);
+  bus_->AssertOnOriginThread();
+
+  MessageReader reader(signal);
+  std::string interface;
+  if (!reader.PopString(&interface)) {
+    LOG(WARNING) << "Property changed signal has wrong parameters: "
+                 << "expected interface name: " << signal->ToString();
+    return;
+  }
+
+  PropertySet* properties = GetProperties(object_path, interface);
+  if (properties)
+    properties->ChangedReceived(signal);
+}
+
+void ObjectManager::OnGetManagedObjects(Response* response) {
+  if (response != NULL) {
+    MessageReader reader(response);
+    MessageReader array_reader(NULL);
+    if (!reader.PopArray(&array_reader))
+      return;
+
+    while (array_reader.HasMoreData()) {
+      MessageReader dict_entry_reader(NULL);
+      ObjectPath object_path;
+      if (!array_reader.PopDictEntry(&dict_entry_reader) ||
+          !dict_entry_reader.PopObjectPath(&object_path))
+        continue;
+
+      UpdateObject(object_path, &dict_entry_reader);
+    }
+
+  } else {
+    LOG(WARNING) << service_name_ << " " << object_path_.value()
+                 << ": Failed to get managed objects";
+  }
+}
+
+void ObjectManager::InterfacesAddedReceived(Signal* signal) {
+  DCHECK(signal);
+  MessageReader reader(signal);
+  ObjectPath object_path;
+  if (!reader.PopObjectPath(&object_path)) {
+    LOG(WARNING) << service_name_ << " " << object_path_.value()
+                 << ": InterfacesAdded signal has incorrect parameters: "
+                 << signal->ToString();
+    return;
+  }
+
+  UpdateObject(object_path, &reader);
+}
+
+void ObjectManager::InterfacesAddedConnected(
+    const std::string& /*interface_name*/,
+    const std::string& /*signal_name*/,
+    bool success) {
+  LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
+                            << ": Failed to connect to InterfacesAdded signal.";
+}
+
+void ObjectManager::InterfacesRemovedReceived(Signal* signal) {
+  DCHECK(signal);
+  MessageReader reader(signal);
+  ObjectPath object_path;
+  std::vector<std::string> interface_names;
+  if (!reader.PopObjectPath(&object_path) ||
+      !reader.PopArrayOfStrings(&interface_names)) {
+    LOG(WARNING) << service_name_ << " " << object_path_.value()
+                 << ": InterfacesRemoved signal has incorrect parameters: "
+                 << signal->ToString();
+    return;
+  }
+
+  for (size_t i = 0; i < interface_names.size(); ++i)
+    RemoveInterface(object_path, interface_names[i]);
+}
+
+void ObjectManager::InterfacesRemovedConnected(
+    const std::string& /*interface_name*/,
+    const std::string& /*signal_name*/,
+    bool success) {
+  LOG_IF(WARNING, !success) << service_name_ << " " << object_path_.value()
+                            << ": Failed to connect to "
+                            << "InterfacesRemoved signal.";
+}
+
+void ObjectManager::UpdateObject(const ObjectPath& object_path,
+                                 MessageReader* reader) {
+  DCHECK(reader);
+  MessageReader array_reader(NULL);
+  if (!reader->PopArray(&array_reader))
+    return;
+
+  while (array_reader.HasMoreData()) {
+    MessageReader dict_entry_reader(NULL);
+    std::string interface_name;
+    if (!array_reader.PopDictEntry(&dict_entry_reader) ||
+        !dict_entry_reader.PopString(&interface_name))
+      continue;
+
+    AddInterface(object_path, interface_name, &dict_entry_reader);
+  }
+}
+
+
+void ObjectManager::AddInterface(const ObjectPath& object_path,
+                                 const std::string& interface_name,
+                                 MessageReader* reader) {
+  InterfaceMap::iterator iiter = interface_map_.find(interface_name);
+  if (iiter == interface_map_.end())
+    return;
+  Interface* interface = iiter->second;
+
+  ObjectMap::iterator oiter = object_map_.find(object_path);
+  Object* object;
+  if (oiter == object_map_.end()) {
+    object = object_map_[object_path] = new Object;
+    object->object_proxy = bus_->GetObjectProxy(service_name_, object_path);
+  } else
+    object = oiter->second;
+
+  Object::PropertiesMap::iterator piter =
+      object->properties_map.find(interface_name);
+  PropertySet* property_set;
+  const bool interface_added = (piter == object->properties_map.end());
+  if (interface_added) {
+    property_set = object->properties_map[interface_name] =
+        interface->CreateProperties(object->object_proxy,
+                                    object_path, interface_name);
+  } else
+    property_set = piter->second;
+
+  property_set->UpdatePropertiesFromReader(reader);
+
+  if (interface_added)
+    interface->ObjectAdded(object_path, interface_name);
+}
+
+void ObjectManager::RemoveInterface(const ObjectPath& object_path,
+                                    const std::string& interface_name) {
+  ObjectMap::iterator oiter = object_map_.find(object_path);
+  if (oiter == object_map_.end())
+    return;
+  Object* object = oiter->second;
+
+  Object::PropertiesMap::iterator piter =
+      object->properties_map.find(interface_name);
+  if (piter == object->properties_map.end())
+    return;
+
+  // Inform the interface before removing the properties structure or object
+  // in case it needs details from them to make its own decisions.
+  InterfaceMap::iterator iiter = interface_map_.find(interface_name);
+  if (iiter != interface_map_.end()) {
+    Interface* interface = iiter->second;
+    interface->ObjectRemoved(object_path, interface_name);
+  }
+
+  delete piter->second;
+  object->properties_map.erase(piter);
+
+  if (object->properties_map.empty()) {
+    object_map_.erase(oiter);
+    delete object;
+  }
+}
+
+void ObjectManager::NameOwnerChanged(const std::string& old_owner,
+                                     const std::string& new_owner) {
+  service_name_owner_ = new_owner;
+
+  if (!old_owner.empty()) {
+    ObjectMap::iterator iter = object_map_.begin();
+    while (iter != object_map_.end()) {
+      ObjectMap::iterator tmp = iter;
+      ++iter;
+
+      // PropertiesMap is mutated by RemoveInterface, and also Object is
+      // destroyed; easier to collect the object path and interface names
+      // and remove them safely.
+      const dbus::ObjectPath object_path = tmp->first;
+      Object* object = tmp->second;
+      std::vector<std::string> interfaces;
+
+      for (Object::PropertiesMap::iterator piter =
+              object->properties_map.begin();
+           piter != object->properties_map.end(); ++piter)
+        interfaces.push_back(piter->first);
+
+      for (std::vector<std::string>::iterator iiter = interfaces.begin();
+           iiter != interfaces.end(); ++iiter)
+        RemoveInterface(object_path, *iiter);
+    }
+
+  }
+
+  if (!new_owner.empty())
+    GetManagedObjects();
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/object_manager.h b/libchrome/dbus/object_manager.h
new file mode 100644
index 0000000..a97495e
--- /dev/null
+++ b/libchrome/dbus/object_manager.h
@@ -0,0 +1,364 @@
+// 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 DBUS_OBJECT_MANAGER_H_
+#define DBUS_OBJECT_MANAGER_H_
+
+#include <stdint.h>
+
+#include <map>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "dbus/object_path.h"
+#include "dbus/property.h"
+
+// Newer D-Bus services implement the Object Manager interface to inform other
+// clients about the objects they export, the properties of those objects, and
+// notification of changes in the set of available objects:
+//     http://dbus.freedesktop.org/doc/dbus-specification.html
+//       #standard-interfaces-objectmanager
+//
+// This interface is very closely tied to the Properties interface, and uses
+// even more levels of nested dictionaries and variants. In addition to
+// simplifying implementation, since there tends to be a single object manager
+// per service, spanning the complete set of objects an interfaces available,
+// the classes implemented here make dealing with this interface simpler.
+//
+// Except where noted, use of this class replaces the need for the code
+// documented in dbus/property.h
+//
+// Client implementation classes should begin by deriving from the
+// dbus::ObjectManager::Interface class, and defining a Properties structure as
+// documented in dbus/property.h.
+//
+// Example:
+//   class ExampleClient : public dbus::ObjectManager::Interface {
+//    public:
+//     struct Properties : public dbus::PropertySet {
+//       dbus::Property<std::string> name;
+//       dbus::Property<uint16_t> version;
+//       dbus::Property<dbus::ObjectPath> parent;
+//       dbus::Property<std::vector<std::string> > children;
+//
+//       Properties(dbus::ObjectProxy* object_proxy,
+//                  const PropertyChangedCallback callback)
+//           : dbus::PropertySet(object_proxy, kExampleInterface, callback) {
+//         RegisterProperty("Name", &name);
+//         RegisterProperty("Version", &version);
+//         RegisterProperty("Parent", &parent);
+//         RegisterProperty("Children", &children);
+//       }
+//       virtual ~Properties() {}
+//     };
+//
+// The link between the implementation class and the object manager is set up
+// in the constructor and removed in the destructor; the class should maintain
+// a pointer to its object manager for use in other methods and establish
+// itself as the implementation class for its interface.
+//
+// Example:
+//   explicit ExampleClient::ExampleClient(dbus::Bus* bus)
+//       : bus_(bus),
+//         weak_ptr_factory_(this) {
+//     object_manager_ = bus_->GetObjectManager(kServiceName, kManagerPath);
+//     object_manager_->RegisterInterface(kInterface, this);
+//   }
+//
+//   virtual ExampleClient::~ExampleClient() {
+//     object_manager_->UnregisterInterface(kInterface);
+//   }
+//
+// The D-Bus thread manager takes care of issuing the necessary call to
+// GetManagedObjects() after the implementation classes have been set up.
+//
+// The object manager interface class has one abstract method that must be
+// implemented by the class to create Properties structures on demand. As well
+// as implementing this, you will want to implement a public GetProperties()
+// method.
+//
+// Example:
+//   dbus::PropertySet* CreateProperties(dbus::ObjectProxy* object_proxy,
+//                                       const std::string& interface_name)
+//       override {
+//     Properties* properties = new Properties(
+//           object_proxy, interface_name,
+//           base::Bind(&PropertyChanged,
+//                      weak_ptr_factory_.GetWeakPtr(),
+//                      object_path));
+//     return static_cast<dbus::PropertySet*>(properties);
+//   }
+//
+//   Properties* GetProperties(const dbus::ObjectPath& object_path) {
+//     return static_cast<Properties*>(
+//         object_manager_->GetProperties(object_path, kInterface));
+//   }
+//
+// Note that unlike classes that only use dbus/property.h there is no need
+// to connect signals or obtain the initial values of properties. The object
+// manager class handles that for you.
+//
+// PropertyChanged is a method of your own to notify your observers of a change
+// in your properties, either as a result of a signal from the Properties
+// interface or from the Object Manager interface. You may also wish to
+// implement the optional ObjectAdded and ObjectRemoved methods of the class
+// to likewise notify observers.
+//
+// When your class needs an object proxy for a given object path, it may
+// obtain it from the object manager. Unlike the equivalent method on the bus
+// this will return NULL if the object is not known.
+//
+//   object_proxy = object_manager_->GetObjectProxy(object_path);
+//   if (object_proxy) {
+//     ...
+//   }
+//
+// There is no need for code using your implementation class to be aware of the
+// use of object manager behind the scenes, the rules for updating properties
+// documented in dbus/property.h still apply.
+
+namespace dbus {
+
+const char kObjectManagerInterface[] = "org.freedesktop.DBus.ObjectManager";
+const char kObjectManagerGetManagedObjects[] = "GetManagedObjects";
+const char kObjectManagerInterfacesAdded[] = "InterfacesAdded";
+const char kObjectManagerInterfacesRemoved[] = "InterfacesRemoved";
+
+class Bus;
+class MessageReader;
+class ObjectProxy;
+class Response;
+class Signal;
+
+// ObjectManager implements both the D-Bus client components of the D-Bus
+// Object Manager interface, as internal methods, and a public API for
+// client classes to utilize.
+class CHROME_DBUS_EXPORT ObjectManager
+    : public base::RefCountedThreadSafe<ObjectManager> {
+public:
+  // ObjectManager::Interface must be implemented by any class wishing to have
+  // its remote objects managed by an ObjectManager.
+  class Interface {
+   public:
+    virtual ~Interface() {}
+
+    // Called by ObjectManager to create a Properties structure for the remote
+    // D-Bus object identified by |object_path| and accessibile through
+    // |object_proxy|. The D-Bus interface name |interface_name| is that passed
+    // to RegisterInterface() by the implementation class.
+    //
+    // The implementation class should create and return an instance of its own
+    // subclass of dbus::PropertySet; ObjectManager will then connect signals
+    // and update the properties from its own internal message reader.
+    virtual PropertySet* CreateProperties(
+        ObjectProxy *object_proxy,
+        const dbus::ObjectPath& object_path,
+        const std::string& interface_name) = 0;
+
+    // Called by ObjectManager to inform the implementation class that an
+    // object has been added with the path |object_path|. The D-Bus interface
+    // name |interface_name| is that passed to RegisterInterface() by the
+    // implementation class.
+    //
+    // If a new object implements multiple interfaces, this method will be
+    // called on each interface implementation with differing values of
+    // |interface_name| as appropriate. An implementation class will only
+    // receive multiple calls if it has registered for multiple interfaces.
+    virtual void ObjectAdded(const ObjectPath& /*object_path*/,
+                             const std::string& /*interface_name*/) {}
+
+    // Called by ObjectManager to inform the implementation class than an
+    // object with the path |object_path| has been removed. Ths D-Bus interface
+    // name |interface_name| is that passed to RegisterInterface() by the
+    // implementation class. Multiple interfaces are handled as with
+    // ObjectAdded().
+    //
+    // This method will be called before the Properties structure and the
+    // ObjectProxy object for the given interface are cleaned up, it is safe
+    // to retrieve them during removal to vary processing.
+    virtual void ObjectRemoved(const ObjectPath& /*object_path*/,
+                               const std::string& /*interface_name*/) {}
+  };
+
+  // Client code should use Bus::GetObjectManager() instead of this constructor.
+  ObjectManager(Bus* bus,
+                const std::string& service_name,
+                const ObjectPath& object_path);
+
+  // Register a client implementation class |interface| for the given D-Bus
+  // interface named in |interface_name|. That object's CreateProperties()
+  // method will be used to create instances of dbus::PropertySet* when
+  // required.
+  void RegisterInterface(const std::string& interface_name,
+                         Interface* interface);
+
+  // Unregister the implementation class for the D-Bus interface named in
+  // |interface_name|, objects and properties of this interface will be
+  // ignored.
+  void UnregisterInterface(const std::string& interface_name);
+
+  // Returns a list of object paths, in an undefined order, of objects known
+  // to this manager.
+  std::vector<ObjectPath> GetObjects();
+
+  // Returns the list of object paths, in an undefined order, of objects
+  // implementing the interface named in |interface_name| known to this manager.
+  std::vector<ObjectPath> GetObjectsWithInterface(
+      const std::string& interface_name);
+
+  // Returns a ObjectProxy pointer for the given |object_path|. Unlike
+  // the equivalent method on Bus this will return NULL if the object
+  // manager has not been informed of that object's existance.
+  ObjectProxy* GetObjectProxy(const ObjectPath& object_path);
+
+  // Returns a PropertySet* pointer for the given |object_path| and
+  // |interface_name|, or NULL if the object manager has not been informed of
+  // that object's existance or the interface's properties. The caller should
+  // cast the returned pointer to the appropriate type, e.g.:
+  //   static_cast<Properties*>(GetProperties(object_path, my_interface));
+  PropertySet* GetProperties(const ObjectPath& object_path,
+                             const std::string& interface_name);
+
+  // Instructs the object manager to refresh its list of managed objects;
+  // automatically called by the D-Bus thread manager, there should never be
+  // a need to call this manually.
+  void GetManagedObjects();
+
+  // Cleans up any match rules and filter functions added by this ObjectManager.
+  // The Bus object will take care of this so you don't have to do it manually.
+  //
+  // BLOCKING CALL.
+  void CleanUp();
+
+ protected:
+  virtual ~ObjectManager();
+
+ private:
+  friend class base::RefCountedThreadSafe<ObjectManager>;
+
+  // Connects the InterfacesAdded and InterfacesRemoved signals and calls
+  // GetManagedObjects. Called from OnSetupMatchRuleAndFilterComplete.
+  void InitializeObjects();
+
+  // Called from the constructor to add a match rule for PropertiesChanged
+  // signals on the DBus thread and set up a corresponding filter function.
+  bool SetupMatchRuleAndFilter();
+
+  // Called on the origin thread once the match rule and filter have been set
+  // up. |success| is false, if an error occurred during set up; it's true
+  // otherwise.
+  void OnSetupMatchRuleAndFilterComplete(bool success);
+
+  // Called by dbus:: when a message is received. This is used to filter
+  // PropertiesChanged signals from the correct sender and relay the event to
+  // the correct PropertySet.
+  static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
+                                              DBusMessage* raw_message,
+                                              void* user_data);
+  DBusHandlerResult HandleMessage(DBusConnection* connection,
+                                  DBusMessage* raw_message);
+
+  // Called when a PropertiesChanged signal is received from the sender.
+  // This method notifies the relevant PropertySet that it should update its
+  // properties based on the received signal. Called from HandleMessage.
+  void NotifyPropertiesChanged(const dbus::ObjectPath object_path,
+                               Signal* signal);
+  void NotifyPropertiesChangedHelper(const dbus::ObjectPath object_path,
+                                     Signal* signal);
+
+  // Called by dbus:: in response to the GetManagedObjects() method call.
+  void OnGetManagedObjects(Response* response);
+
+  // Called by dbus:: when an InterfacesAdded signal is received and initially
+  // connected.
+  void InterfacesAddedReceived(Signal* signal);
+  void InterfacesAddedConnected(const std::string& interface_name,
+                                const std::string& signal_name,
+                                bool success);
+
+  // Called by dbus:: when an InterfacesRemoved signal is received and
+  // initially connected.
+  void InterfacesRemovedReceived(Signal* signal);
+  void InterfacesRemovedConnected(const std::string& interface_name,
+                                  const std::string& signal_name,
+                                  bool success);
+
+  // Updates the map entry for the object with path |object_path| using the
+  // D-Bus message in |reader|, which should consist of an dictionary mapping
+  // interface names to properties dictionaries as recieved by both the
+  // GetManagedObjects() method return and the InterfacesAdded() signal.
+  void UpdateObject(const ObjectPath& object_path, MessageReader* reader);
+
+  // Updates the properties structure of the object with path |object_path|
+  // for the interface named |interface_name| using the D-Bus message in
+  // |reader| which should consist of the properties dictionary for that
+  // interface.
+  //
+  // Called by UpdateObjects() for each interface in the dictionary; this
+  // method takes care of both creating the entry in the ObjectMap and
+  // ObjectProxy if required, as well as the PropertySet instance for that
+  // interface if necessary.
+  void AddInterface(const ObjectPath& object_path,
+                    const std::string& interface_name,
+                    MessageReader* reader);
+
+  // Removes the properties structure of the object with path |object_path|
+  // for the interfaces named |interface_name|.
+  //
+  // If no further interfaces remain, the entry in the ObjectMap is discarded.
+  void RemoveInterface(const ObjectPath& object_path,
+                       const std::string& interface_name);
+
+  // Removes all objects and interfaces from the object manager when
+  // |old_owner| is not the empty string and/or re-requests the set of managed
+  // objects when |new_owner| is not the empty string.
+  void NameOwnerChanged(const std::string& old_owner,
+                        const std::string& new_owner);
+
+  Bus* bus_;
+  std::string service_name_;
+  std::string service_name_owner_;
+  std::string match_rule_;
+  ObjectPath object_path_;
+  ObjectProxy* object_proxy_;
+  bool setup_success_;
+  bool cleanup_called_;
+
+  // Maps the name of an interface to the implementation class used for
+  // instantiating PropertySet structures for that interface's properties.
+  typedef std::map<std::string, Interface*> InterfaceMap;
+  InterfaceMap interface_map_;
+
+  // Each managed object consists of a ObjectProxy used to make calls
+  // against that object and a collection of D-Bus interface names and their
+  // associated PropertySet structures.
+  struct Object {
+    Object();
+    ~Object();
+
+    ObjectProxy* object_proxy;
+
+    // Maps the name of an interface to the specific PropertySet structure
+    // of that interface's properties.
+    typedef std::map<const std::string, PropertySet*> PropertiesMap;
+    PropertiesMap properties_map;
+  };
+
+  // Maps the object path of an object to the Object structure.
+  typedef std::map<const ObjectPath, Object*> ObjectMap;
+  ObjectMap object_map_;
+
+  // Weak pointer factory for generating 'this' pointers that might live longer
+  // than we do.
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate its weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<ObjectManager> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectManager);
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_OBJECT_MANAGER_H_
diff --git a/libchrome/dbus/object_path.cc b/libchrome/dbus/object_path.cc
new file mode 100644
index 0000000..8606b6b
--- /dev/null
+++ b/libchrome/dbus/object_path.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/object_path.h"
+
+#include <ostream>
+
+#include "dbus/string_util.h"
+
+namespace dbus {
+
+bool ObjectPath::IsValid() const {
+  return IsValidObjectPath(value_);
+}
+
+bool ObjectPath::operator<(const ObjectPath& that) const {
+  return value_ < that.value_;
+}
+
+bool ObjectPath::operator==(const ObjectPath& that) const {
+  return value_ == that.value_;
+}
+
+bool ObjectPath::operator!=(const ObjectPath& that) const {
+  return value_ != that.value_;
+}
+
+void PrintTo(const ObjectPath& path, std::ostream* out) {
+  *out << path.value();
+}
+
+} // namespace dbus
diff --git a/libchrome/dbus/object_path.h b/libchrome/dbus/object_path.h
new file mode 100644
index 0000000..072c23d
--- /dev/null
+++ b/libchrome/dbus/object_path.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 DBUS_OBJECT_PATH_H_
+#define DBUS_OBJECT_PATH_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "dbus/dbus_export.h"
+
+namespace dbus {
+
+// ObjectPath is a type used to distinguish D-Bus object paths from simple
+// strings, especially since normal practice is that these should be only
+// initialized from static constants or obtained from remote objects and no
+// assumptions about their value made.
+class CHROME_DBUS_EXPORT ObjectPath {
+ public:
+  // Permit initialization without a value for passing to
+  // dbus::MessageReader::PopObjectPath to fill in and from std::string
+  // objects.
+  //
+  // The compiler synthesised copy constructor and assignment operator are
+  // sufficient for our needs, as is implicit initialization of a std::string
+  // from a string constant.
+  ObjectPath() {}
+  explicit ObjectPath(const std::string& value) : value_(value) {}
+
+  // Retrieves value as a std::string.
+  const std::string& value() const { return value_; }
+
+  // Returns true if the value is a valid object path.
+  bool IsValid() const;
+
+  // Permit sufficient comparison to allow an ObjectPath to be used as a
+  // key in a std::map.
+  bool operator<(const ObjectPath&) const;
+
+  // Permit testing for equality, required for mocks to work and useful for
+  // observers.
+  bool operator==(const ObjectPath&) const;
+  bool operator!=(const ObjectPath&) const;
+
+ private:
+  std::string value_;
+};
+
+// This is required by gtest to print a readable output on test failures.
+CHROME_DBUS_EXPORT void PrintTo(const ObjectPath& path, std::ostream* out);
+
+}  // namespace dbus
+
+#endif  // DBUS_OBJECT_PATH_H_
diff --git a/libchrome/dbus/object_proxy.cc b/libchrome/dbus/object_proxy.cc
new file mode 100644
index 0000000..ce02551
--- /dev/null
+++ b/libchrome/dbus/object_proxy.cc
@@ -0,0 +1,716 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/object_proxy.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "dbus/bus.h"
+#include "dbus/dbus_statistics.h"
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/scoped_dbus_error.h"
+#include "dbus/util.h"
+
+namespace dbus {
+
+namespace {
+
+const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
+const char kErrorObjectUnknown[] = "org.freedesktop.DBus.Error.UnknownObject";
+
+// Used for success ratio histograms. 1 for success, 0 for failure.
+const int kSuccessRatioHistogramMaxValue = 2;
+
+// The path of D-Bus Object sending NameOwnerChanged signal.
+const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
+
+// The D-Bus Object interface.
+const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
+
+// The D-Bus Object address.
+const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
+
+// The NameOwnerChanged member in |kDBusSystemObjectInterface|.
+const char kNameOwnerChangedMember[] = "NameOwnerChanged";
+
+// An empty function used for ObjectProxy::EmptyResponseCallback().
+void EmptyResponseCallbackBody(Response* /*response*/) {
+}
+
+}  // namespace
+
+ObjectProxy::ObjectProxy(Bus* bus,
+                         const std::string& service_name,
+                         const ObjectPath& object_path,
+                         int options)
+    : bus_(bus),
+      service_name_(service_name),
+      object_path_(object_path),
+      ignore_service_unknown_errors_(
+          options & IGNORE_SERVICE_UNKNOWN_ERRORS) {
+}
+
+ObjectProxy::~ObjectProxy() {
+  DCHECK(pending_calls_.empty());
+}
+
+// Originally we tried to make |method_call| a const reference, but we
+// gave up as dbus_connection_send_with_reply_and_block() takes a
+// non-const pointer of DBusMessage as the second parameter.
+std::unique_ptr<Response> ObjectProxy::CallMethodAndBlockWithErrorDetails(
+    MethodCall* method_call,
+    int timeout_ms,
+    ScopedDBusError* error) {
+  bus_->AssertOnDBusThread();
+
+  if (!bus_->Connect() ||
+      !method_call->SetDestination(service_name_) ||
+      !method_call->SetPath(object_path_))
+    return std::unique_ptr<Response>();
+
+  DBusMessage* request_message = method_call->raw_message();
+
+  // Send the message synchronously.
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  DBusMessage* response_message =
+      bus_->SendWithReplyAndBlock(request_message, timeout_ms, error->get());
+  // Record if the method call is successful, or not. 1 if successful.
+  UMA_HISTOGRAM_ENUMERATION("DBus.SyncMethodCallSuccess",
+                            response_message ? 1 : 0,
+                            kSuccessRatioHistogramMaxValue);
+  statistics::AddBlockingSentMethodCall(service_name_,
+                                        method_call->GetInterface(),
+                                        method_call->GetMember());
+
+  if (!response_message) {
+    LogMethodCallFailure(method_call->GetInterface(),
+                         method_call->GetMember(),
+                         error->is_set() ? error->name() : "unknown error type",
+                         error->is_set() ? error->message() : "");
+    return std::unique_ptr<Response>();
+  }
+  // Record time spent for the method call. Don't include failures.
+  UMA_HISTOGRAM_TIMES("DBus.SyncMethodCallTime",
+                      base::TimeTicks::Now() - start_time);
+
+  return Response::FromRawMessage(response_message);
+}
+
+std::unique_ptr<Response> ObjectProxy::CallMethodAndBlock(
+    MethodCall* method_call,
+    int timeout_ms) {
+  ScopedDBusError error;
+  return CallMethodAndBlockWithErrorDetails(method_call, timeout_ms, &error);
+}
+
+void ObjectProxy::CallMethod(MethodCall* method_call,
+                             int timeout_ms,
+                             ResponseCallback callback) {
+  CallMethodWithErrorCallback(method_call, timeout_ms, callback,
+                              base::Bind(&ObjectProxy::OnCallMethodError,
+                                         this,
+                                         method_call->GetInterface(),
+                                         method_call->GetMember(),
+                                         callback));
+}
+
+void ObjectProxy::CallMethodWithErrorCallback(MethodCall* method_call,
+                                              int timeout_ms,
+                                              ResponseCallback callback,
+                                              ErrorCallback error_callback) {
+  bus_->AssertOnOriginThread();
+
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+
+  if (!method_call->SetDestination(service_name_) ||
+      !method_call->SetPath(object_path_)) {
+    // In case of a failure, run the error callback with NULL.
+    DBusMessage* response_message = NULL;
+    base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
+                                    this,
+                                    callback,
+                                    error_callback,
+                                    start_time,
+                                    response_message);
+    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
+    return;
+  }
+
+  // Increment the reference count so we can safely reference the
+  // underlying request message until the method call is complete. This
+  // will be unref'ed in StartAsyncMethodCall().
+  DBusMessage* request_message = method_call->raw_message();
+  dbus_message_ref(request_message);
+
+  base::Closure task = base::Bind(&ObjectProxy::StartAsyncMethodCall,
+                                  this,
+                                  timeout_ms,
+                                  request_message,
+                                  callback,
+                                  error_callback,
+                                  start_time);
+  statistics::AddSentMethodCall(service_name_,
+                                method_call->GetInterface(),
+                                method_call->GetMember());
+
+  // Wait for the response in the D-Bus thread.
+  bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
+}
+
+void ObjectProxy::ConnectToSignal(const std::string& interface_name,
+                                  const std::string& signal_name,
+                                  SignalCallback signal_callback,
+                                  OnConnectedCallback on_connected_callback) {
+  bus_->AssertOnOriginThread();
+
+  if (bus_->HasDBusThread()) {
+    base::PostTaskAndReplyWithResult(
+        bus_->GetDBusTaskRunner(), FROM_HERE,
+        base::Bind(&ObjectProxy::ConnectToSignalInternal, this, interface_name,
+                   signal_name, signal_callback),
+        base::Bind(on_connected_callback, interface_name, signal_name));
+  } else {
+    // If the bus doesn't have a dedicated dbus thread we need to call
+    // ConnectToSignalInternal directly otherwise we might miss a signal
+    // that is currently queued if we do a PostTask.
+    const bool success =
+        ConnectToSignalInternal(interface_name, signal_name, signal_callback);
+    on_connected_callback.Run(interface_name, signal_name, success);
+  }
+}
+
+void ObjectProxy::SetNameOwnerChangedCallback(
+    NameOwnerChangedCallback callback) {
+  bus_->AssertOnOriginThread();
+
+  name_owner_changed_callback_ = callback;
+}
+
+void ObjectProxy::WaitForServiceToBeAvailable(
+    WaitForServiceToBeAvailableCallback callback) {
+  bus_->AssertOnOriginThread();
+
+  wait_for_service_to_be_available_callbacks_.push_back(callback);
+  bus_->GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ObjectProxy::WaitForServiceToBeAvailableInternal, this));
+}
+
+void ObjectProxy::Detach() {
+  bus_->AssertOnDBusThread();
+
+  if (bus_->is_connected())
+    bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
+
+  for (const auto& match_rule : match_rules_) {
+    ScopedDBusError error;
+    bus_->RemoveMatch(match_rule, error.get());
+    if (error.is_set()) {
+      // There is nothing we can do to recover, so just print the error.
+      LOG(ERROR) << "Failed to remove match rule: " << match_rule;
+    }
+  }
+  match_rules_.clear();
+
+  for (auto* pending_call : pending_calls_) {
+    dbus_pending_call_cancel(pending_call);
+    dbus_pending_call_unref(pending_call);
+  }
+  pending_calls_.clear();
+}
+
+// static
+ObjectProxy::ResponseCallback ObjectProxy::EmptyResponseCallback() {
+  return base::Bind(&EmptyResponseCallbackBody);
+}
+
+ObjectProxy::OnPendingCallIsCompleteData::OnPendingCallIsCompleteData(
+    ObjectProxy* in_object_proxy,
+    ResponseCallback in_response_callback,
+    ErrorCallback in_error_callback,
+    base::TimeTicks in_start_time)
+    : object_proxy(in_object_proxy),
+      response_callback(in_response_callback),
+      error_callback(in_error_callback),
+      start_time(in_start_time) {
+}
+
+ObjectProxy::OnPendingCallIsCompleteData::~OnPendingCallIsCompleteData() {
+}
+
+void ObjectProxy::StartAsyncMethodCall(int timeout_ms,
+                                       DBusMessage* request_message,
+                                       ResponseCallback response_callback,
+                                       ErrorCallback error_callback,
+                                       base::TimeTicks start_time) {
+  bus_->AssertOnDBusThread();
+
+  if (!bus_->Connect() || !bus_->SetUpAsyncOperations()) {
+    // In case of a failure, run the error callback with NULL.
+    DBusMessage* response_message = NULL;
+    base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
+                                    this,
+                                    response_callback,
+                                    error_callback,
+                                    start_time,
+                                    response_message);
+    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
+
+    dbus_message_unref(request_message);
+    return;
+  }
+
+  DBusPendingCall* pending_call = NULL;
+
+  bus_->SendWithReply(request_message, &pending_call, timeout_ms);
+
+  // Prepare the data we'll be passing to OnPendingCallIsCompleteThunk().
+  // The data will be deleted in OnPendingCallIsCompleteThunk().
+  OnPendingCallIsCompleteData* data =
+      new OnPendingCallIsCompleteData(this, response_callback, error_callback,
+                                      start_time);
+
+  // This returns false only when unable to allocate memory.
+  const bool success = dbus_pending_call_set_notify(
+      pending_call,
+      &ObjectProxy::OnPendingCallIsCompleteThunk,
+      data,
+      &DeleteVoidPointer<OnPendingCallIsCompleteData>);
+  CHECK(success) << "Unable to allocate memory";
+  pending_calls_.insert(pending_call);
+
+  // It's now safe to unref the request message.
+  dbus_message_unref(request_message);
+}
+
+void ObjectProxy::OnPendingCallIsComplete(DBusPendingCall* pending_call,
+                                          ResponseCallback response_callback,
+                                          ErrorCallback error_callback,
+                                          base::TimeTicks start_time) {
+  bus_->AssertOnDBusThread();
+
+  DBusMessage* response_message = dbus_pending_call_steal_reply(pending_call);
+  base::Closure task = base::Bind(&ObjectProxy::RunResponseCallback,
+                                  this,
+                                  response_callback,
+                                  error_callback,
+                                  start_time,
+                                  response_message);
+  bus_->GetOriginTaskRunner()->PostTask(FROM_HERE, task);
+
+  // Remove the pending call from the set.
+  pending_calls_.erase(pending_call);
+  dbus_pending_call_unref(pending_call);
+}
+
+void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
+                                      ErrorCallback error_callback,
+                                      base::TimeTicks start_time,
+                                      DBusMessage* response_message) {
+  bus_->AssertOnOriginThread();
+
+  bool method_call_successful = false;
+  if (!response_message) {
+    // The response is not received.
+    error_callback.Run(NULL);
+  } else if (dbus_message_get_type(response_message) ==
+             DBUS_MESSAGE_TYPE_ERROR) {
+    // This will take |response_message| and release (unref) it.
+    std::unique_ptr<ErrorResponse> error_response(
+        ErrorResponse::FromRawMessage(response_message));
+    error_callback.Run(error_response.get());
+    // Delete the message  on the D-Bus thread. See below for why.
+    bus_->GetDBusTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&base::DeletePointer<ErrorResponse>,
+                   error_response.release()));
+  } else {
+    // This will take |response_message| and release (unref) it.
+    std::unique_ptr<Response> response(
+        Response::FromRawMessage(response_message));
+    // The response is successfully received.
+    response_callback.Run(response.get());
+    // The message should be deleted on the D-Bus thread for a complicated
+    // reason:
+    //
+    // libdbus keeps track of the number of bytes in the incoming message
+    // queue to ensure that the data size in the queue is manageable. The
+    // bookkeeping is partly done via dbus_message_unref(), and immediately
+    // asks the client code (Chrome) to stop monitoring the underlying
+    // socket, if the number of bytes exceeds a certian number, which is set
+    // to 63MB, per dbus-transport.cc:
+    //
+    //   /* Try to default to something that won't totally hose the system,
+    //    * but doesn't impose too much of a limitation.
+    //    */
+    //   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
+    //
+    // The monitoring of the socket is done on the D-Bus thread (see Watch
+    // class in bus.cc), hence we should stop the monitoring from D-Bus
+    // thread, not from the current thread here, which is likely UI thread.
+    bus_->GetDBusTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&base::DeletePointer<Response>, response.release()));
+
+    method_call_successful = true;
+    // Record time spent for the method call. Don't include failures.
+    UMA_HISTOGRAM_TIMES("DBus.AsyncMethodCallTime",
+                        base::TimeTicks::Now() - start_time);
+  }
+  // Record if the method call is successful, or not. 1 if successful.
+  UMA_HISTOGRAM_ENUMERATION("DBus.AsyncMethodCallSuccess",
+                            method_call_successful,
+                            kSuccessRatioHistogramMaxValue);
+}
+
+void ObjectProxy::OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
+                                               void* user_data) {
+  OnPendingCallIsCompleteData* data =
+      reinterpret_cast<OnPendingCallIsCompleteData*>(user_data);
+  ObjectProxy* self = data->object_proxy;
+  self->OnPendingCallIsComplete(pending_call,
+                                data->response_callback,
+                                data->error_callback,
+                                data->start_time);
+}
+
+bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
+  bus_->AssertOnDBusThread();
+
+  if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
+    return false;
+
+  bus_->AddFilterFunction(&ObjectProxy::HandleMessageThunk, this);
+
+  // Add a match_rule listening NameOwnerChanged for the well-known name
+  // |service_name_|.
+  const std::string name_owner_changed_match_rule =
+      base::StringPrintf(
+          "type='signal',interface='org.freedesktop.DBus',"
+          "member='NameOwnerChanged',path='/org/freedesktop/DBus',"
+          "sender='org.freedesktop.DBus',arg0='%s'",
+          service_name_.c_str());
+
+  const bool success =
+      AddMatchRuleWithoutCallback(name_owner_changed_match_rule,
+                                  "org.freedesktop.DBus.NameOwnerChanged");
+
+  // Try getting the current name owner. It's not guaranteed that we can get
+  // the name owner at this moment, as the service may not yet be started. If
+  // that's the case, we'll get the name owner via NameOwnerChanged signal,
+  // as soon as the service is started.
+  UpdateNameOwnerAndBlock();
+
+  return success;
+}
+
+bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
+                                          const std::string& signal_name,
+                                          SignalCallback signal_callback) {
+  bus_->AssertOnDBusThread();
+
+  if (!ConnectToNameOwnerChangedSignal())
+    return false;
+
+  const std::string absolute_signal_name =
+      GetAbsoluteMemberName(interface_name, signal_name);
+
+  // Add a match rule so the signal goes through HandleMessage().
+  const std::string match_rule =
+      base::StringPrintf("type='signal', interface='%s', path='%s'",
+                         interface_name.c_str(),
+                         object_path_.value().c_str());
+  return AddMatchRuleWithCallback(match_rule,
+                                  absolute_signal_name,
+                                  signal_callback);
+}
+
+void ObjectProxy::WaitForServiceToBeAvailableInternal() {
+  bus_->AssertOnDBusThread();
+
+  if (!ConnectToNameOwnerChangedSignal()) {  // Failed to connect to the signal.
+    const bool service_is_ready = false;
+    bus_->GetOriginTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
+                   this, service_is_ready));
+    return;
+  }
+
+  const bool service_is_available = !service_name_owner_.empty();
+  if (service_is_available) {  // Service is already available.
+    bus_->GetOriginTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
+                   this, service_is_available));
+    return;
+  }
+}
+
+DBusHandlerResult ObjectProxy::HandleMessage(DBusConnection*,
+                                             DBusMessage* raw_message) {
+  bus_->AssertOnDBusThread();
+
+  if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  // raw_message will be unrefed on exit of the function. Increment the
+  // reference so we can use it in Signal.
+  dbus_message_ref(raw_message);
+  std::unique_ptr<Signal> signal(Signal::FromRawMessage(raw_message));
+
+  // Verify the signal comes from the object we're proxying for, this is
+  // our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
+  // allow other object proxies to handle instead.
+  const ObjectPath path = signal->GetPath();
+  if (path != object_path_) {
+    if (path.value() == kDBusSystemObjectPath &&
+        signal->GetMember() == kNameOwnerChangedMember) {
+      // Handle NameOwnerChanged separately
+      return HandleNameOwnerChanged(std::move(signal));
+    }
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  const std::string interface = signal->GetInterface();
+  const std::string member = signal->GetMember();
+
+  statistics::AddReceivedSignal(service_name_, interface, member);
+
+  // Check if we know about the signal.
+  const std::string absolute_signal_name = GetAbsoluteMemberName(
+      interface, member);
+  MethodTable::const_iterator iter = method_table_.find(absolute_signal_name);
+  if (iter == method_table_.end()) {
+    // Don't know about the signal.
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+  VLOG(1) << "Signal received: " << signal->ToString();
+
+  std::string sender = signal->GetSender();
+  if (service_name_owner_ != sender) {
+    LOG(ERROR) << "Rejecting a message from a wrong sender.";
+    UMA_HISTOGRAM_COUNTS("DBus.RejectedSignalCount", 1);
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  const base::TimeTicks start_time = base::TimeTicks::Now();
+  if (bus_->HasDBusThread()) {
+    // Post a task to run the method in the origin thread.
+    // Transfer the ownership of |signal| to RunMethod().
+    // |released_signal| will be deleted in RunMethod().
+    Signal* released_signal = signal.release();
+    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
+                                          base::Bind(&ObjectProxy::RunMethod,
+                                                     this,
+                                                     start_time,
+                                                     iter->second,
+                                                     released_signal));
+  } else {
+    const base::TimeTicks start_time = base::TimeTicks::Now();
+    // If the D-Bus thread is not used, just call the callback on the
+    // current thread. Transfer the ownership of |signal| to RunMethod().
+    Signal* released_signal = signal.release();
+    RunMethod(start_time, iter->second, released_signal);
+  }
+
+  // We don't return DBUS_HANDLER_RESULT_HANDLED for signals because other
+  // objects may be interested in them. (e.g. Signals from org.freedesktop.DBus)
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+void ObjectProxy::RunMethod(base::TimeTicks start_time,
+                            std::vector<SignalCallback> signal_callbacks,
+                            Signal* signal) {
+  bus_->AssertOnOriginThread();
+
+  for (std::vector<SignalCallback>::iterator iter = signal_callbacks.begin();
+       iter != signal_callbacks.end(); ++iter)
+    iter->Run(signal);
+
+  // Delete the message on the D-Bus thread. See comments in
+  // RunResponseCallback().
+  bus_->GetDBusTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&base::DeletePointer<Signal>, signal));
+
+  // Record time spent for handling the signal.
+  UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
+                      base::TimeTicks::Now() - start_time);
+}
+
+DBusHandlerResult ObjectProxy::HandleMessageThunk(
+    DBusConnection* connection,
+    DBusMessage* raw_message,
+    void* user_data) {
+  ObjectProxy* self = reinterpret_cast<ObjectProxy*>(user_data);
+  return self->HandleMessage(connection, raw_message);
+}
+
+void ObjectProxy::LogMethodCallFailure(
+    const base::StringPiece& interface_name,
+    const base::StringPiece& method_name,
+    const base::StringPiece& error_name,
+    const base::StringPiece& error_message) const {
+  if (ignore_service_unknown_errors_ &&
+      (error_name == kErrorServiceUnknown || error_name == kErrorObjectUnknown))
+    return;
+
+  std::ostringstream msg;
+  msg << "Failed to call method: " << interface_name << "." << method_name
+      << ": object_path= " << object_path_.value()
+      << ": " << error_name << ": " << error_message;
+
+  // "UnknownObject" indicates that an object or service is no longer available,
+  // e.g. a Shill network service has gone out of range. Treat these as warnings
+  // not errors.
+  if (error_name == kErrorObjectUnknown)
+    LOG(WARNING) << msg.str();
+  else
+    LOG(ERROR) << msg.str();
+}
+
+void ObjectProxy::OnCallMethodError(const std::string& interface_name,
+                                    const std::string& method_name,
+                                    ResponseCallback response_callback,
+                                    ErrorResponse* error_response) {
+  if (error_response) {
+    // Error message may contain the error message as string.
+    MessageReader reader(error_response);
+    std::string error_message;
+    reader.PopString(&error_message);
+    LogMethodCallFailure(interface_name,
+                         method_name,
+                         error_response->GetErrorName(),
+                         error_message);
+  }
+  response_callback.Run(NULL);
+}
+
+bool ObjectProxy::AddMatchRuleWithCallback(
+    const std::string& match_rule,
+    const std::string& absolute_signal_name,
+    SignalCallback signal_callback) {
+  DCHECK(!match_rule.empty());
+  DCHECK(!absolute_signal_name.empty());
+  bus_->AssertOnDBusThread();
+
+  if (match_rules_.find(match_rule) == match_rules_.end()) {
+    ScopedDBusError error;
+    bus_->AddMatch(match_rule, error.get());
+    if (error.is_set()) {
+      LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
+                 << error.name() << ": " << error.message();
+      return false;
+    } else {
+      // Store the match rule, so that we can remove this in Detach().
+      match_rules_.insert(match_rule);
+      // Add the signal callback to the method table.
+      method_table_[absolute_signal_name].push_back(signal_callback);
+      return true;
+    }
+  } else {
+    // We already have the match rule.
+    method_table_[absolute_signal_name].push_back(signal_callback);
+    return true;
+  }
+}
+
+bool ObjectProxy::AddMatchRuleWithoutCallback(
+    const std::string& match_rule,
+    const std::string& absolute_signal_name) {
+  DCHECK(!match_rule.empty());
+  DCHECK(!absolute_signal_name.empty());
+  bus_->AssertOnDBusThread();
+
+  if (match_rules_.find(match_rule) != match_rules_.end())
+    return true;
+
+  ScopedDBusError error;
+  bus_->AddMatch(match_rule, error.get());
+  if (error.is_set()) {
+    LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
+               << error.name() << ": " << error.message();
+    return false;
+  }
+  // Store the match rule, so that we can remove this in Detach().
+  match_rules_.insert(match_rule);
+  return true;
+}
+
+void ObjectProxy::UpdateNameOwnerAndBlock() {
+  bus_->AssertOnDBusThread();
+  // Errors should be suppressed here, as the service may not be yet running
+  // when connecting to signals of the service, which is just fine.
+  // The ObjectProxy will be notified when the service is launched via
+  // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
+  service_name_owner_ =
+      bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
+}
+
+DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
+    std::unique_ptr<Signal> signal) {
+  DCHECK(signal);
+  bus_->AssertOnDBusThread();
+
+  // Confirm the validity of the NameOwnerChanged signal.
+  if (signal->GetMember() == kNameOwnerChangedMember &&
+      signal->GetInterface() == kDBusSystemObjectInterface &&
+      signal->GetSender() == kDBusSystemObjectAddress) {
+    MessageReader reader(signal.get());
+    std::string name, old_owner, new_owner;
+    if (reader.PopString(&name) &&
+        reader.PopString(&old_owner) &&
+        reader.PopString(&new_owner) &&
+        name == service_name_) {
+      service_name_owner_ = new_owner;
+      bus_->GetOriginTaskRunner()->PostTask(
+          FROM_HERE,
+          base::Bind(&ObjectProxy::RunNameOwnerChangedCallback,
+                     this, old_owner, new_owner));
+
+      const bool service_is_available = !service_name_owner_.empty();
+      if (service_is_available) {
+        bus_->GetOriginTaskRunner()->PostTask(
+            FROM_HERE,
+            base::Bind(&ObjectProxy::RunWaitForServiceToBeAvailableCallbacks,
+                       this, service_is_available));
+      }
+    }
+  }
+
+  // Always return unhandled to let other object proxies handle the same
+  // signal.
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+void ObjectProxy::RunNameOwnerChangedCallback(const std::string& old_owner,
+                                              const std::string& new_owner) {
+  bus_->AssertOnOriginThread();
+  if (!name_owner_changed_callback_.is_null())
+    name_owner_changed_callback_.Run(old_owner, new_owner);
+}
+
+void ObjectProxy::RunWaitForServiceToBeAvailableCallbacks(
+    bool service_is_available) {
+  bus_->AssertOnOriginThread();
+
+  std::vector<WaitForServiceToBeAvailableCallback> callbacks;
+  callbacks.swap(wait_for_service_to_be_available_callbacks_);
+  for (size_t i = 0; i < callbacks.size(); ++i)
+    callbacks[i].Run(service_is_available);
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/object_proxy.h b/libchrome/dbus/object_proxy.h
new file mode 100644
index 0000000..033e886
--- /dev/null
+++ b/libchrome/dbus/object_proxy.h
@@ -0,0 +1,333 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_OBJECT_PROXY_H_
+#define DBUS_OBJECT_PROXY_H_
+
+#include <dbus/dbus.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
+#include "dbus/dbus_export.h"
+#include "dbus/object_path.h"
+
+namespace dbus {
+
+class Bus;
+class ErrorResponse;
+class MethodCall;
+class Response;
+class ScopedDBusError;
+class Signal;
+
+// ObjectProxy is used to communicate with remote objects, mainly for
+// calling methods of these objects.
+//
+// ObjectProxy is a ref counted object, to ensure that |this| of the
+// object is alive when callbacks referencing |this| are called; the
+// bus always holds at least one of those references so object proxies
+// always last as long as the bus that created them.
+class CHROME_DBUS_EXPORT ObjectProxy
+    : public base::RefCountedThreadSafe<ObjectProxy> {
+ public:
+  // Client code should use Bus::GetObjectProxy() or
+  // Bus::GetObjectProxyWithOptions() instead of this constructor.
+  ObjectProxy(Bus* bus,
+              const std::string& service_name,
+              const ObjectPath& object_path,
+              int options);
+
+  // Options to be OR-ed together when calling Bus::GetObjectProxyWithOptions().
+  // Set the IGNORE_SERVICE_UNKNOWN_ERRORS option to silence logging of
+  // org.freedesktop.DBus.Error.ServiceUnknown errors and
+  // org.freedesktop.DBus.Error.ObjectUnknown errors.
+  enum Options {
+    DEFAULT_OPTIONS = 0,
+    IGNORE_SERVICE_UNKNOWN_ERRORS = 1 << 0
+  };
+
+  // Special timeout constants.
+  //
+  // The constants correspond to DBUS_TIMEOUT_USE_DEFAULT and
+  // DBUS_TIMEOUT_INFINITE. Here we use literal numbers instead of these
+  // macros as these aren't defined with D-Bus earlier than 1.4.12.
+  enum {
+    TIMEOUT_USE_DEFAULT = -1,
+    TIMEOUT_INFINITE = 0x7fffffff,
+  };
+
+  // Called when an error response is returned or no response is returned.
+  // Used for CallMethodWithErrorCallback().
+  typedef base::Callback<void(ErrorResponse*)> ErrorCallback;
+
+  // Called when the response is returned. Used for CallMethod().
+  typedef base::Callback<void(Response*)> ResponseCallback;
+
+  // Called when a signal is received. Signal* is the incoming signal.
+  typedef base::Callback<void (Signal*)> SignalCallback;
+
+  // Called when NameOwnerChanged signal is received.
+  typedef base::Callback<void(
+      const std::string& old_owner,
+      const std::string& new_owner)> NameOwnerChangedCallback;
+
+  // Called when the service becomes available.
+  typedef base::Callback<void(
+      bool service_is_available)> WaitForServiceToBeAvailableCallback;
+
+  // Called when the object proxy is connected to the signal.
+  // Parameters:
+  // - the interface name.
+  // - the signal name.
+  // - whether it was successful or not.
+  typedef base::Callback<void (const std::string&, const std::string&, bool)>
+      OnConnectedCallback;
+
+  // Calls the method of the remote object and blocks until the response
+  // is returned. Returns NULL on error with the error details specified
+  // in the |error| object.
+  //
+  // BLOCKING CALL.
+  virtual std::unique_ptr<Response> CallMethodAndBlockWithErrorDetails(
+      MethodCall* method_call,
+      int timeout_ms,
+      ScopedDBusError* error);
+
+  // Calls the method of the remote object and blocks until the response
+  // is returned. Returns NULL on error.
+  //
+  // BLOCKING CALL.
+  virtual std::unique_ptr<Response> CallMethodAndBlock(MethodCall* method_call,
+                                                       int timeout_ms);
+
+  // Requests to call the method of the remote object.
+  //
+  // |callback| will be called in the origin thread, once the method call
+  // is complete. As it's called in the origin thread, |callback| can
+  // safely reference objects in the origin thread (i.e. UI thread in most
+  // cases). If the caller is not interested in the response from the
+  // method (i.e. calling a method that does not return a value),
+  // EmptyResponseCallback() can be passed to the |callback| parameter.
+  //
+  // If the method call is successful, a pointer to Response object will
+  // be passed to the callback. If unsuccessful, NULL will be passed to
+  // the callback.
+  //
+  // Must be called in the origin thread.
+  virtual void CallMethod(MethodCall* method_call,
+                          int timeout_ms,
+                          ResponseCallback callback);
+
+  // Requests to call the method of the remote object.
+  //
+  // |callback| and |error_callback| will be called in the origin thread, once
+  // the method call is complete. As it's called in the origin thread,
+  // |callback| can safely reference objects in the origin thread (i.e.
+  // UI thread in most cases). If the caller is not interested in the response
+  // from the method (i.e. calling a method that does not return a value),
+  // EmptyResponseCallback() can be passed to the |callback| parameter.
+  //
+  // If the method call is successful, a pointer to Response object will
+  // be passed to the callback. If unsuccessful, the error callback will be
+  // called and a pointer to ErrorResponse object will be passed to the error
+  // callback if available, otherwise NULL will be passed.
+  //
+  // Must be called in the origin thread.
+  virtual void CallMethodWithErrorCallback(MethodCall* method_call,
+                                           int timeout_ms,
+                                           ResponseCallback callback,
+                                           ErrorCallback error_callback);
+
+  // Requests to connect to the signal from the remote object.
+  //
+  // |signal_callback| will be called in the origin thread, when the
+  // signal is received from the remote object. As it's called in the
+  // origin thread, |signal_callback| can safely reference objects in the
+  // origin thread (i.e. UI thread in most cases).
+  //
+  // |on_connected_callback| is called when the object proxy is connected
+  // to the signal, or failed to be connected, in the origin thread.
+  //
+  // If a SignalCallback has already been registered for the given
+  // |interface_name| and |signal_name|, |signal_callback| will be
+  // added to the list of callbacks for |interface_name| and
+  // |signal_name|.
+  //
+  // Must be called in the origin thread.
+  virtual void ConnectToSignal(const std::string& interface_name,
+                               const std::string& signal_name,
+                               SignalCallback signal_callback,
+                               OnConnectedCallback on_connected_callback);
+
+  // Sets a callback for "NameOwnerChanged" signal. The callback is called on
+  // the origin thread when D-Bus system sends "NameOwnerChanged" for the name
+  // represented by |service_name_|.
+  virtual void SetNameOwnerChangedCallback(NameOwnerChangedCallback callback);
+
+  // Runs the callback as soon as the service becomes available.
+  virtual void WaitForServiceToBeAvailable(
+      WaitForServiceToBeAvailableCallback callback);
+
+  // Detaches from the remote object. The Bus object will take care of
+  // detaching so you don't have to do this manually.
+  //
+  // BLOCKING CALL.
+  virtual void Detach();
+
+  const ObjectPath& object_path() const { return object_path_; }
+
+  // Returns an empty callback that does nothing. Can be used for
+  // CallMethod().
+  static ResponseCallback EmptyResponseCallback();
+
+ protected:
+  // This is protected, so we can define sub classes.
+  virtual ~ObjectProxy();
+
+ private:
+  friend class base::RefCountedThreadSafe<ObjectProxy>;
+
+  // Struct of data we'll be passing from StartAsyncMethodCall() to
+  // OnPendingCallIsCompleteThunk().
+  struct OnPendingCallIsCompleteData {
+    OnPendingCallIsCompleteData(ObjectProxy* in_object_proxy,
+                                ResponseCallback in_response_callback,
+                                ErrorCallback error_callback,
+                                base::TimeTicks start_time);
+    ~OnPendingCallIsCompleteData();
+
+    ObjectProxy* object_proxy;
+    ResponseCallback response_callback;
+    ErrorCallback error_callback;
+    base::TimeTicks start_time;
+  };
+
+  // Starts the async method call. This is a helper function to implement
+  // CallMethod().
+  void StartAsyncMethodCall(int timeout_ms,
+                            DBusMessage* request_message,
+                            ResponseCallback response_callback,
+                            ErrorCallback error_callback,
+                            base::TimeTicks start_time);
+
+  // Called when the pending call is complete.
+  void OnPendingCallIsComplete(DBusPendingCall* pending_call,
+                               ResponseCallback response_callback,
+                               ErrorCallback error_callback,
+                               base::TimeTicks start_time);
+
+  // Runs the response callback with the given response object.
+  void RunResponseCallback(ResponseCallback response_callback,
+                           ErrorCallback error_callback,
+                           base::TimeTicks start_time,
+                           DBusMessage* response_message);
+
+  // Redirects the function call to OnPendingCallIsComplete().
+  static void OnPendingCallIsCompleteThunk(DBusPendingCall* pending_call,
+                                           void* user_data);
+
+  // Connects to NameOwnerChanged signal.
+  bool ConnectToNameOwnerChangedSignal();
+
+  // Helper function for ConnectToSignal().
+  bool ConnectToSignalInternal(const std::string& interface_name,
+                               const std::string& signal_name,
+                               SignalCallback signal_callback);
+
+  // Helper function for WaitForServiceToBeAvailable().
+  void WaitForServiceToBeAvailableInternal();
+
+  // Handles the incoming request messages and dispatches to the signal
+  // callbacks.
+  DBusHandlerResult HandleMessage(DBusConnection* connection,
+                                  DBusMessage* raw_message);
+
+  // Runs the method. Helper function for HandleMessage().
+  void RunMethod(base::TimeTicks start_time,
+                 std::vector<SignalCallback> signal_callbacks,
+                 Signal* signal);
+
+  // Redirects the function call to HandleMessage().
+  static DBusHandlerResult HandleMessageThunk(DBusConnection* connection,
+                                              DBusMessage* raw_message,
+                                              void* user_data);
+
+  // Helper method for logging response errors appropriately.
+  void LogMethodCallFailure(const base::StringPiece& interface_name,
+                            const base::StringPiece& method_name,
+                            const base::StringPiece& error_name,
+                            const base::StringPiece& error_message) const;
+
+  // Used as ErrorCallback by CallMethod().
+  void OnCallMethodError(const std::string& interface_name,
+                         const std::string& method_name,
+                         ResponseCallback response_callback,
+                         ErrorResponse* error_response);
+
+  // Adds the match rule to the bus and associate the callback with the signal.
+  bool AddMatchRuleWithCallback(const std::string& match_rule,
+                                const std::string& absolute_signal_name,
+                                SignalCallback signal_callback);
+
+  // Adds the match rule to the bus so that HandleMessage can see the signal.
+  bool AddMatchRuleWithoutCallback(const std::string& match_rule,
+                                   const std::string& absolute_signal_name);
+
+  // Calls D-Bus's GetNameOwner method synchronously to update
+  // |service_name_owner_| with the current owner of |service_name_|.
+  //
+  // BLOCKING CALL.
+  void UpdateNameOwnerAndBlock();
+
+  // Handles NameOwnerChanged signal from D-Bus's special message bus.
+  DBusHandlerResult HandleNameOwnerChanged(
+      std::unique_ptr<dbus::Signal> signal);
+
+  // Runs |name_owner_changed_callback_|.
+  void RunNameOwnerChangedCallback(const std::string& old_owner,
+                                   const std::string& new_owner);
+
+  // Runs |wait_for_service_to_be_available_callbacks_|.
+  void RunWaitForServiceToBeAvailableCallbacks(bool service_is_available);
+
+  scoped_refptr<Bus> bus_;
+  std::string service_name_;
+  ObjectPath object_path_;
+
+  // The method table where keys are absolute signal names (i.e. interface
+  // name + signal name), and values are lists of the corresponding callbacks.
+  typedef std::map<std::string, std::vector<SignalCallback> > MethodTable;
+  MethodTable method_table_;
+
+  // The callback called when NameOwnerChanged signal is received.
+  NameOwnerChangedCallback name_owner_changed_callback_;
+
+  // Called when the service becomes available.
+  std::vector<WaitForServiceToBeAvailableCallback>
+      wait_for_service_to_be_available_callbacks_;
+
+  std::set<std::string> match_rules_;
+
+  const bool ignore_service_unknown_errors_;
+
+  // Known name owner of the well-known bus name represented by |service_name_|.
+  std::string service_name_owner_;
+
+  std::set<DBusPendingCall*> pending_calls_;
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectProxy);
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_OBJECT_PROXY_H_
diff --git a/libchrome/dbus/property.cc b/libchrome/dbus/property.cc
new file mode 100644
index 0000000..aa58436
--- /dev/null
+++ b/libchrome/dbus/property.cc
@@ -0,0 +1,679 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/property.h"
+
+#include <stddef.h>
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/object_proxy.h"
+
+namespace dbus {
+
+//
+// PropertyBase implementation.
+//
+
+PropertyBase::PropertyBase() : property_set_(nullptr), is_valid_(false) {}
+
+PropertyBase::~PropertyBase() {}
+
+void PropertyBase::Init(PropertySet* property_set, const std::string& name) {
+  DCHECK(!property_set_);
+  property_set_ = property_set;
+  is_valid_ = false;
+  name_ = name;
+}
+
+//
+// PropertySet implementation.
+//
+
+PropertySet::PropertySet(
+    ObjectProxy* object_proxy,
+    const std::string& interface,
+    const PropertyChangedCallback& property_changed_callback)
+    : object_proxy_(object_proxy),
+      interface_(interface),
+      property_changed_callback_(property_changed_callback),
+      weak_ptr_factory_(this) {}
+
+PropertySet::~PropertySet() {
+}
+
+void PropertySet::RegisterProperty(const std::string& name,
+                                   PropertyBase* property) {
+  property->Init(this, name);
+  properties_map_[name] = property;
+}
+
+void PropertySet::ConnectSignals() {
+  DCHECK(object_proxy_);
+  object_proxy_->ConnectToSignal(
+      kPropertiesInterface,
+      kPropertiesChanged,
+      base::Bind(&PropertySet::ChangedReceived,
+                 weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&PropertySet::ChangedConnected,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+
+void PropertySet::ChangedReceived(Signal* signal) {
+  DCHECK(signal);
+  MessageReader reader(signal);
+
+  std::string interface;
+  if (!reader.PopString(&interface)) {
+    LOG(WARNING) << "Property changed signal has wrong parameters: "
+                 << "expected interface name: " << signal->ToString();
+    return;
+  }
+
+  if (interface != this->interface())
+    return;
+
+  if (!UpdatePropertiesFromReader(&reader)) {
+    LOG(WARNING) << "Property changed signal has wrong parameters: "
+                 << "expected dictionary: " << signal->ToString();
+  }
+
+  if (!InvalidatePropertiesFromReader(&reader)) {
+    LOG(WARNING) << "Property changed signal has wrong parameters: "
+                 << "expected array to invalidate: " << signal->ToString();
+  }
+}
+
+void PropertySet::ChangedConnected(const std::string& /*interface_name*/,
+                                   const std::string& signal_name,
+                                   bool success) {
+  LOG_IF(WARNING, !success) << "Failed to connect to " << signal_name
+                            << "signal.";
+}
+
+
+void PropertySet::Get(PropertyBase* property, GetCallback callback) {
+  MethodCall method_call(kPropertiesInterface, kPropertiesGet);
+  MessageWriter writer(&method_call);
+  writer.AppendString(interface());
+  writer.AppendString(property->name());
+
+  DCHECK(object_proxy_);
+  object_proxy_->CallMethod(&method_call,
+                            ObjectProxy::TIMEOUT_USE_DEFAULT,
+                            base::Bind(&PropertySet::OnGet,
+                                       GetWeakPtr(),
+                                       property,
+                                       callback));
+}
+
+void PropertySet::OnGet(PropertyBase* property, GetCallback callback,
+                        Response* response) {
+  if (!response) {
+    LOG(WARNING) << property->name() << ": Get: failed.";
+    return;
+  }
+
+  MessageReader reader(response);
+  if (property->PopValueFromReader(&reader)) {
+    property->set_valid(true);
+    NotifyPropertyChanged(property->name());
+  } else {
+    if (property->is_valid()) {
+      property->set_valid(false);
+      NotifyPropertyChanged(property->name());
+    }
+  }
+
+  if (!callback.is_null())
+    callback.Run(response);
+}
+
+bool PropertySet::GetAndBlock(PropertyBase* property) {
+  MethodCall method_call(kPropertiesInterface, kPropertiesGet);
+  MessageWriter writer(&method_call);
+  writer.AppendString(interface());
+  writer.AppendString(property->name());
+
+  DCHECK(object_proxy_);
+  std::unique_ptr<dbus::Response> response(object_proxy_->CallMethodAndBlock(
+      &method_call, ObjectProxy::TIMEOUT_USE_DEFAULT));
+
+  if (!response.get()) {
+    LOG(WARNING) << property->name() << ": GetAndBlock: failed.";
+    return false;
+  }
+
+  MessageReader reader(response.get());
+  if (property->PopValueFromReader(&reader)) {
+    property->set_valid(true);
+    NotifyPropertyChanged(property->name());
+  } else {
+    if (property->is_valid()) {
+      property->set_valid(false);
+      NotifyPropertyChanged(property->name());
+    }
+  }
+  return true;
+}
+
+void PropertySet::GetAll() {
+  MethodCall method_call(kPropertiesInterface, kPropertiesGetAll);
+  MessageWriter writer(&method_call);
+  writer.AppendString(interface());
+
+  DCHECK(object_proxy_);
+  object_proxy_->CallMethod(&method_call,
+                            ObjectProxy::TIMEOUT_USE_DEFAULT,
+                            base::Bind(&PropertySet::OnGetAll,
+                                       weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PropertySet::OnGetAll(Response* response) {
+  if (!response) {
+    LOG(WARNING) << "GetAll request failed for: " << interface_;
+    return;
+  }
+
+  MessageReader reader(response);
+  if (!UpdatePropertiesFromReader(&reader)) {
+    LOG(WARNING) << "GetAll response has wrong parameters: "
+                 << "expected dictionary: " << response->ToString();
+  }
+}
+
+void PropertySet::Set(PropertyBase* property, SetCallback callback) {
+  MethodCall method_call(kPropertiesInterface, kPropertiesSet);
+  MessageWriter writer(&method_call);
+  writer.AppendString(interface());
+  writer.AppendString(property->name());
+  property->AppendSetValueToWriter(&writer);
+
+  DCHECK(object_proxy_);
+  object_proxy_->CallMethod(&method_call,
+                            ObjectProxy::TIMEOUT_USE_DEFAULT,
+                            base::Bind(&PropertySet::OnSet,
+                                       GetWeakPtr(),
+                                       property,
+                                       callback));
+}
+
+bool PropertySet::SetAndBlock(PropertyBase* property) {
+  MethodCall method_call(kPropertiesInterface, kPropertiesSet);
+  MessageWriter writer(&method_call);
+  writer.AppendString(interface());
+  writer.AppendString(property->name());
+  property->AppendSetValueToWriter(&writer);
+
+  DCHECK(object_proxy_);
+  std::unique_ptr<dbus::Response> response(object_proxy_->CallMethodAndBlock(
+      &method_call, ObjectProxy::TIMEOUT_USE_DEFAULT));
+  if (response.get())
+    return true;
+  return false;
+}
+
+void PropertySet::OnSet(PropertyBase* property,
+                        SetCallback callback,
+                        Response* response) {
+  LOG_IF(WARNING, !response) << property->name() << ": Set: failed.";
+  if (!callback.is_null())
+    callback.Run(response);
+}
+
+bool PropertySet::UpdatePropertiesFromReader(MessageReader* reader) {
+  DCHECK(reader);
+  MessageReader array_reader(NULL);
+  if (!reader->PopArray(&array_reader))
+    return false;
+
+  while (array_reader.HasMoreData()) {
+    MessageReader dict_entry_reader(NULL);
+    if (array_reader.PopDictEntry(&dict_entry_reader))
+      UpdatePropertyFromReader(&dict_entry_reader);
+  }
+
+  return true;
+}
+
+bool PropertySet::UpdatePropertyFromReader(MessageReader* reader) {
+  DCHECK(reader);
+
+  std::string name;
+  if (!reader->PopString(&name))
+    return false;
+
+  PropertiesMap::iterator it = properties_map_.find(name);
+  if (it == properties_map_.end())
+    return false;
+
+  PropertyBase* property = it->second;
+  if (property->PopValueFromReader(reader)) {
+    property->set_valid(true);
+    NotifyPropertyChanged(name);
+    return true;
+  } else {
+    if (property->is_valid()) {
+      property->set_valid(false);
+      NotifyPropertyChanged(property->name());
+    }
+    return false;
+  }
+}
+
+bool PropertySet::InvalidatePropertiesFromReader(MessageReader* reader) {
+  DCHECK(reader);
+  MessageReader array_reader(NULL);
+  if (!reader->PopArray(&array_reader))
+    return false;
+
+  while (array_reader.HasMoreData()) {
+    std::string name;
+    if (!array_reader.PopString(&name))
+      return false;
+
+    PropertiesMap::iterator it = properties_map_.find(name);
+    if (it == properties_map_.end())
+      continue;
+
+    PropertyBase* property = it->second;
+    if (property->is_valid()) {
+      property->set_valid(false);
+      NotifyPropertyChanged(property->name());
+    }
+  }
+
+  return true;
+}
+
+void PropertySet::NotifyPropertyChanged(const std::string& name) {
+  if (!property_changed_callback_.is_null())
+    property_changed_callback_.Run(name);
+}
+
+//
+// Property<Byte> specialization.
+//
+
+template <>
+Property<uint8_t>::Property()
+    : value_(0) {}
+
+template <>
+bool Property<uint8_t>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfByte(&value_);
+}
+
+template <>
+void Property<uint8_t>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfByte(set_value_);
+}
+
+//
+// Property<bool> specialization.
+//
+
+template <>
+Property<bool>::Property() : value_(false) {
+}
+
+template <>
+bool Property<bool>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfBool(&value_);
+}
+
+template <>
+void Property<bool>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfBool(set_value_);
+}
+
+//
+// Property<int16_t> specialization.
+//
+
+template <>
+Property<int16_t>::Property()
+    : value_(0) {}
+
+template <>
+bool Property<int16_t>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfInt16(&value_);
+}
+
+template <>
+void Property<int16_t>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfInt16(set_value_);
+}
+
+//
+// Property<uint16_t> specialization.
+//
+
+template <>
+Property<uint16_t>::Property()
+    : value_(0) {}
+
+template <>
+bool Property<uint16_t>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfUint16(&value_);
+}
+
+template <>
+void Property<uint16_t>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfUint16(set_value_);
+}
+
+//
+// Property<int32_t> specialization.
+//
+
+template <>
+Property<int32_t>::Property()
+    : value_(0) {}
+
+template <>
+bool Property<int32_t>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfInt32(&value_);
+}
+
+template <>
+void Property<int32_t>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfInt32(set_value_);
+}
+
+//
+// Property<uint32_t> specialization.
+//
+
+template <>
+Property<uint32_t>::Property()
+    : value_(0) {}
+
+template <>
+bool Property<uint32_t>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfUint32(&value_);
+}
+
+template <>
+void Property<uint32_t>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfUint32(set_value_);
+}
+
+//
+// Property<int64_t> specialization.
+//
+
+template <>
+Property<int64_t>::Property()
+    : value_(0), set_value_(0) {}
+
+template <>
+bool Property<int64_t>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfInt64(&value_);
+}
+
+template <>
+void Property<int64_t>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfInt64(set_value_);
+}
+
+//
+// Property<uint64_t> specialization.
+//
+
+template <>
+Property<uint64_t>::Property()
+    : value_(0) {}
+
+template <>
+bool Property<uint64_t>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfUint64(&value_);
+}
+
+template <>
+void Property<uint64_t>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfUint64(set_value_);
+}
+
+//
+// Property<double> specialization.
+//
+
+template <>
+Property<double>::Property() : value_(0.0) {
+}
+
+template <>
+bool Property<double>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfDouble(&value_);
+}
+
+template <>
+void Property<double>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfDouble(set_value_);
+}
+
+//
+// Property<std::string> specialization.
+//
+
+template <>
+bool Property<std::string>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfString(&value_);
+}
+
+template <>
+void Property<std::string>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfString(set_value_);
+}
+
+//
+// Property<ObjectPath> specialization.
+//
+
+template <>
+bool Property<ObjectPath>::PopValueFromReader(MessageReader* reader) {
+  return reader->PopVariantOfObjectPath(&value_);
+}
+
+template <>
+void Property<ObjectPath>::AppendSetValueToWriter(MessageWriter* writer) {
+  writer->AppendVariantOfObjectPath(set_value_);
+}
+
+//
+// Property<std::vector<std::string> > specialization.
+//
+
+template <>
+bool Property<std::vector<std::string> >::PopValueFromReader(
+    MessageReader* reader) {
+  MessageReader variant_reader(NULL);
+  if (!reader->PopVariant(&variant_reader))
+    return false;
+
+  value_.clear();
+  return variant_reader.PopArrayOfStrings(&value_);
+}
+
+template <>
+void Property<std::vector<std::string> >::AppendSetValueToWriter(
+    MessageWriter* writer) {
+  MessageWriter variant_writer(NULL);
+  writer->OpenVariant("as", &variant_writer);
+  variant_writer.AppendArrayOfStrings(set_value_);
+  writer->CloseContainer(&variant_writer);
+}
+
+//
+// Property<std::vector<ObjectPath> > specialization.
+//
+
+template <>
+bool Property<std::vector<ObjectPath> >::PopValueFromReader(
+    MessageReader* reader) {
+  MessageReader variant_reader(NULL);
+  if (!reader->PopVariant(&variant_reader))
+    return false;
+
+  value_.clear();
+  return variant_reader.PopArrayOfObjectPaths(&value_);
+}
+
+template <>
+void Property<std::vector<ObjectPath> >::AppendSetValueToWriter(
+    MessageWriter* writer) {
+  MessageWriter variant_writer(NULL);
+  writer->OpenVariant("ao", &variant_writer);
+  variant_writer.AppendArrayOfObjectPaths(set_value_);
+  writer->CloseContainer(&variant_writer);
+}
+
+//
+// Property<std::vector<uint8_t> > specialization.
+//
+
+template <>
+bool Property<std::vector<uint8_t>>::PopValueFromReader(MessageReader* reader) {
+  MessageReader variant_reader(NULL);
+  if (!reader->PopVariant(&variant_reader))
+    return false;
+
+  value_.clear();
+  const uint8_t* bytes = NULL;
+  size_t length = 0;
+  if (!variant_reader.PopArrayOfBytes(&bytes, &length))
+    return false;
+  value_.assign(bytes, bytes + length);
+  return true;
+}
+
+template <>
+void Property<std::vector<uint8_t>>::AppendSetValueToWriter(
+    MessageWriter* writer) {
+  MessageWriter variant_writer(NULL);
+  writer->OpenVariant("ay", &variant_writer);
+  variant_writer.AppendArrayOfBytes(set_value_.data(), set_value_.size());
+  writer->CloseContainer(&variant_writer);
+}
+
+//
+// Property<std::map<std::string, std::string>> specialization.
+//
+
+template <>
+bool Property<std::map<std::string, std::string>>::PopValueFromReader(
+    MessageReader* reader) {
+  MessageReader variant_reader(NULL);
+  MessageReader array_reader(NULL);
+  if (!reader->PopVariant(&variant_reader) ||
+      !variant_reader.PopArray(&array_reader))
+    return false;
+  value_.clear();
+  while (array_reader.HasMoreData()) {
+    dbus::MessageReader dict_entry_reader(NULL);
+    if (!array_reader.PopDictEntry(&dict_entry_reader))
+      return false;
+    std::string key;
+    std::string value;
+    if (!dict_entry_reader.PopString(&key) ||
+        !dict_entry_reader.PopString(&value))
+      return false;
+    value_[key] = value;
+  }
+  return true;
+}
+
+template <>
+void Property<std::map<std::string, std::string>>::AppendSetValueToWriter(
+    MessageWriter* writer) {
+  MessageWriter variant_writer(NULL);
+  MessageWriter dict_writer(NULL);
+  writer->OpenVariant("a{ss}", &variant_writer);
+  variant_writer.OpenArray("{ss}", &dict_writer);
+  for (const auto& pair : set_value_) {
+    dbus::MessageWriter entry_writer(NULL);
+    dict_writer.OpenDictEntry(&entry_writer);
+    entry_writer.AppendString(pair.first);
+    entry_writer.AppendString(pair.second);
+    dict_writer.CloseContainer(&entry_writer);
+  }
+  variant_writer.CloseContainer(&dict_writer);
+  writer->CloseContainer(&variant_writer);
+}
+
+//
+// Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>
+// specialization.
+//
+
+template <>
+bool Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
+    PopValueFromReader(MessageReader* reader) {
+  MessageReader variant_reader(NULL);
+  MessageReader array_reader(NULL);
+  if (!reader->PopVariant(&variant_reader) ||
+      !variant_reader.PopArray(&array_reader))
+    return false;
+
+  value_.clear();
+  while (array_reader.HasMoreData()) {
+    dbus::MessageReader struct_reader(NULL);
+    if (!array_reader.PopStruct(&struct_reader))
+      return false;
+
+    std::pair<std::vector<uint8_t>, uint16_t> entry;
+    const uint8_t* bytes = NULL;
+    size_t length = 0;
+    if (!struct_reader.PopArrayOfBytes(&bytes, &length))
+      return false;
+    entry.first.assign(bytes, bytes + length);
+    if (!struct_reader.PopUint16(&entry.second))
+      return false;
+    value_.push_back(entry);
+  }
+  return true;
+}
+
+template <>
+void Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
+    AppendSetValueToWriter(MessageWriter* writer) {
+  MessageWriter variant_writer(NULL);
+  MessageWriter array_writer(NULL);
+  writer->OpenVariant("a(ayq)", &variant_writer);
+  variant_writer.OpenArray("(ayq)", &array_writer);
+  for (const auto& pair : set_value_) {
+    dbus::MessageWriter struct_writer(nullptr);
+    array_writer.OpenStruct(&struct_writer);
+    struct_writer.AppendArrayOfBytes(std::get<0>(pair).data(),
+                                     std::get<0>(pair).size());
+    struct_writer.AppendUint16(std::get<1>(pair));
+    array_writer.CloseContainer(&struct_writer);
+  }
+  variant_writer.CloseContainer(&array_writer);
+  writer->CloseContainer(&variant_writer);
+}
+
+template class Property<uint8_t>;
+template class Property<bool>;
+template class Property<int16_t>;
+template class Property<uint16_t>;
+template class Property<int32_t>;
+template class Property<uint32_t>;
+template class Property<int64_t>;
+template class Property<uint64_t>;
+template class Property<double>;
+template class Property<std::string>;
+template class Property<ObjectPath>;
+template class Property<std::vector<std::string> >;
+template class Property<std::vector<ObjectPath> >;
+template class Property<std::vector<uint8_t>>;
+template class Property<std::map<std::string, std::string>>;
+template class Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
+
+}  // namespace dbus
diff --git a/libchrome/dbus/property.h b/libchrome/dbus/property.h
new file mode 100644
index 0000000..efbad22
--- /dev/null
+++ b/libchrome/dbus/property.h
@@ -0,0 +1,617 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_PROPERTY_H_
+#define DBUS_PROPERTY_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "dbus/dbus_export.h"
+#include "dbus/message.h"
+#include "dbus/object_proxy.h"
+
+// D-Bus objects frequently provide sets of properties accessed via a
+// standard interface of method calls and signals to obtain the current value,
+// set a new value and be notified of changes to the value. Unfortunately this
+// interface makes heavy use of variants and dictionaries of variants. The
+// classes defined here make dealing with properties in a type-safe manner
+// possible.
+//
+// Client implementation classes should define a Properties structure, deriving
+// from the PropertySet class defined here. This structure should contain a
+// member for each property defined as an instance of the Property<> class,
+// specifying the type to the template. Finally the structure should chain up
+// to the PropertySet constructor, and then call RegisterProperty() for each
+// property defined to associate them with their string name.
+//
+// Example:
+//   class ExampleClient {
+//    public:
+//     struct Properties : public dbus::PropertySet {
+//       dbus::Property<std::string> name;
+//       dbus::Property<uint16_t> version;
+//       dbus::Property<dbus::ObjectPath> parent;
+//       dbus::Property<std::vector<std::string> > children;
+//
+//       Properties(dbus::ObjectProxy* object_proxy,
+//                  const PropertyChangedCallback callback)
+//           : dbus::PropertySet(object_proxy, "com.example.DBus", callback) {
+//         RegisterProperty("Name", &name);
+//         RegisterProperty("Version", &version);
+//         RegisterProperty("Parent", &parent);
+//         RegisterProperty("Children", &children);
+//       }
+//       virtual ~Properties() {}
+//     };
+//
+// The Properties structure requires a pointer to the object proxy of the
+// actual object to track, and after construction should have signals
+// connected to that object and initial values set by calling ConnectSignals()
+// and GetAll(). The structure should not outlive the object proxy, so it
+// is recommended that the lifecycle of both be managed together.
+//
+// Example (continued):
+//
+//     typedef std::map<std::pair<dbus::ObjectProxy*, Properties*> > Object;
+//     typedef std::map<dbus::ObjectPath, Object> ObjectMap;
+//     ObjectMap object_map_;
+//
+//     dbus::ObjectProxy* GetObjectProxy(const dbus::ObjectPath& object_path) {
+//       return GetObject(object_path).first;
+//     }
+//
+//     Properties* GetProperties(const dbus::ObjectPath& object_path) {
+//       return GetObject(object_path).second;
+//     }
+//
+//     Object GetObject(const dbus::ObjectPath& object_path) {
+//       ObjectMap::iterator it = object_map_.find(object_path);
+//       if (it != object_map_.end())
+//         return it->second;
+//
+//       dbus::ObjectProxy* object_proxy = bus->GetObjectProxy(...);
+//       // connect signals, etc.
+//
+//       Properties* properties = new Properties(
+//           object_proxy,
+//           base::Bind(&PropertyChanged,
+//                      weak_ptr_factory_.GetWeakPtr(),
+//                      object_path));
+//       properties->ConnectSignals();
+//       properties->GetAll();
+//
+//       Object object = std::make_pair(object_proxy, properties);
+//       object_map_[object_path] = object;
+//       return object;
+//     }
+//  };
+//
+// This now allows code using the client implementation to access properties
+// in a type-safe manner, and assuming the PropertyChanged callback is
+// propogated up to observers, be notified of changes. A typical access of
+// the current value of the name property would be:
+//
+//   ExampleClient::Properties* p = example_client->GetProperties(object_path);
+//   std::string name = p->name.value();
+//
+// Normally these values are updated from signals emitted by the remote object,
+// in case an explicit round-trip is needed to obtain the current value, the
+// Get() method can be used and indicates whether or not the value update was
+// successful. The updated value can be obtained in the callback using the
+// value() method.
+//
+//   p->children.Get(base::Bind(&OnGetChildren));
+//
+// A new value can be set using the Set() method, the callback indicates
+// success only; it is up to the remote object when (and indeed if) it updates
+// the property value, and whether it emits a signal or a Get() call is
+// required to obtain it.
+//
+//   p->version.Set(20, base::Bind(&OnSetVersion))
+
+namespace dbus {
+
+// D-Bus Properties interface constants, declared here rather than
+// in property.cc because template methods use them.
+const char kPropertiesInterface[] = "org.freedesktop.DBus.Properties";
+const char kPropertiesGetAll[] = "GetAll";
+const char kPropertiesGet[] = "Get";
+const char kPropertiesSet[] = "Set";
+const char kPropertiesChanged[] = "PropertiesChanged";
+
+class PropertySet;
+
+// PropertyBase is an abstract base-class consisting of the parts of
+// the Property<> template that are not type-specific, such as the
+// associated PropertySet, property name, and the type-unsafe parts
+// used by PropertySet.
+class CHROME_DBUS_EXPORT PropertyBase {
+ public:
+  PropertyBase();
+  virtual ~PropertyBase();
+
+  // Initializes the |property_set| and property |name| so that method
+  // calls may be made from this class. This method is called by
+  // PropertySet::RegisterProperty() passing |this| for |property_set| so
+  // there should be no need to call it directly. If you do beware that
+  // no ownership or reference to |property_set| is taken so that object
+  // must outlive this one.
+  void Init(PropertySet* property_set, const std::string& name);
+
+  // Retrieves the name of this property, this may be useful in observers
+  // to avoid specifying the name in more than once place, e.g.
+  //
+  //   void Client::PropertyChanged(const dbus::ObjectPath& object_path,
+  //                                const std::string &property_name) {
+  //     Properties& properties = GetProperties(object_path);
+  //     if (property_name == properties.version.name()) {
+  //       // Handle version property changing
+  //     }
+  //   }
+  const std::string& name() const { return name_; }
+
+  // Returns true if property is valid, false otherwise.
+  bool is_valid() const { return is_valid_; }
+
+  // Allows to mark Property as valid or invalid.
+  void set_valid(bool is_valid) { is_valid_ = is_valid; }
+
+  // Method used by PropertySet to retrieve the value from a MessageReader,
+  // no knowledge of the contained type is required, this method returns
+  // true if its expected type was found, false if not.
+  // Implementation provided by specialization.
+  virtual bool PopValueFromReader(MessageReader* reader) = 0;
+
+  // Method used by PropertySet to append the set value to a MessageWriter,
+  // no knowledge of the contained type is required.
+  // Implementation provided by specialization.
+  virtual void AppendSetValueToWriter(MessageWriter* writer) = 0;
+
+  // Method used by test and stub implementations of dbus::PropertySet::Set
+  // to replace the property value with the set value without using a
+  // dbus::MessageReader.
+  virtual void ReplaceValueWithSetValue() = 0;
+
+ protected:
+  // Retrieves the associated property set.
+  PropertySet* property_set() { return property_set_; }
+
+ private:
+  // Pointer to the PropertySet instance that this instance is a member of,
+  // no ownership is taken and |property_set_| must outlive this class.
+  PropertySet* property_set_;
+
+  bool is_valid_;
+
+  // Name of the property.
+  std::string name_;
+
+  DISALLOW_COPY_AND_ASSIGN(PropertyBase);
+};
+
+// PropertySet groups a collection of properties for a remote object
+// together into a single structure, fixing their types and name such
+// that calls made through it are type-safe.
+//
+// Clients always sub-class this to add the properties, and should always
+// provide a constructor that chains up to this and then calls
+// RegisterProperty() for each property defined.
+//
+// After creation, client code should call ConnectSignals() and most likely
+// GetAll() to seed initial values and update as changes occur.
+class CHROME_DBUS_EXPORT PropertySet {
+ public:
+  // Callback for changes to cached values of properties, either notified
+  // via signal, or as a result of calls to Get() and GetAll(). The |name|
+  // argument specifies the name of the property changed.
+  typedef base::Callback<void(const std::string& name)> PropertyChangedCallback;
+
+  // Constructs a property set, where |object_proxy| specifies the proxy for
+  // the/ remote object that these properties are for, care should be taken to
+  // ensure that this object does not outlive the lifetime of the proxy;
+  // |interface| specifies the D-Bus interface of these properties, and
+  // |property_changed_callback| specifies the callback for when properties
+  // are changed, this may be a NULL callback.
+  PropertySet(ObjectProxy* object_proxy, const std::string& interface,
+              const PropertyChangedCallback& property_changed_callback);
+
+  // Destructor; we don't hold on to any references or memory that needs
+  // explicit clean-up, but clang thinks we might.
+  virtual ~PropertySet();
+
+  // Registers a property, generally called from the subclass constructor;
+  // pass the |name| of the property as used in method calls and signals,
+  // and the pointer to the |property| member of the structure. This will
+  // call the PropertyBase::Init method.
+  void RegisterProperty(const std::string& name, PropertyBase* property);
+
+  // Connects property change notification signals to the object, generally
+  // called immediately after the object is created and before calls to other
+  // methods. Sub-classes may override to use different D-Bus signals.
+  virtual void ConnectSignals();
+
+  // Methods connected by ConnectSignals() and called by dbus:: when
+  // a property is changed. Sub-classes may override if the property
+  // changed signal provides different arguments.
+  virtual void ChangedReceived(Signal* signal);
+  virtual void ChangedConnected(const std::string& interface_name,
+                                const std::string& signal_name,
+                                bool success);
+
+  // Callback for Get() method, |success| indicates whether or not the
+  // value could be retrived, if true the new value can be obtained by
+  // calling value() on the property.
+  typedef base::Callback<void(bool success)> GetCallback;
+
+  // Requests an updated value from the remote object for |property|
+  // incurring a round-trip. |callback| will be called when the new
+  // value is available. This may not be implemented by some interfaces,
+  // and may be overriden by sub-classes if interfaces use different
+  // method calls.
+  virtual void Get(PropertyBase* property, GetCallback callback);
+  virtual void OnGet(PropertyBase* property, GetCallback callback,
+                     Response* response);
+
+  // The synchronous version of Get().
+  // This should never be used on an interactive thread.
+  virtual bool GetAndBlock(PropertyBase* property);
+
+  // Queries the remote object for values of all properties and updates
+  // initial values. Sub-classes may override to use a different D-Bus
+  // method, or if the remote object does not support retrieving all
+  // properties, either ignore or obtain each property value individually.
+  virtual void GetAll();
+  virtual void OnGetAll(Response* response);
+
+  // Callback for Set() method, |success| indicates whether or not the
+  // new property value was accepted by the remote object.
+  typedef base::Callback<void(bool success)> SetCallback;
+
+  // Requests that the remote object for |property| change the property to
+  // its new value. |callback| will be called to indicate the success or
+  // failure of the request, however the new value may not be available
+  // depending on the remote object. This method may be overridden by
+  // sub-classes if interfaces use different method calls.
+  virtual void Set(PropertyBase* property, SetCallback callback);
+  virtual void OnSet(PropertyBase* property, SetCallback callback,
+                     Response* response);
+
+  // The synchronous version of Set().
+  // This should never be used on an interactive thread.
+  virtual bool SetAndBlock(PropertyBase* property);
+
+  // Update properties by reading an array of dictionary entries, each
+  // containing a string with the name and a variant with the value, from
+  // |message_reader|. Returns false if message is in incorrect format.
+  bool UpdatePropertiesFromReader(MessageReader* reader);
+
+  // Updates a single property by reading a string with the name and a
+  // variant with the value from |message_reader|. Returns false if message
+  // is in incorrect format, or property type doesn't match.
+  bool UpdatePropertyFromReader(MessageReader* reader);
+
+  // Calls the property changed callback passed to the constructor, used
+  // by sub-classes that do not call UpdatePropertiesFromReader() or
+  // UpdatePropertyFromReader(). Takes the |name| of the changed property.
+  void NotifyPropertyChanged(const std::string& name);
+
+  // Retrieves the object proxy this property set was initialized with,
+  // provided for sub-classes overriding methods that make D-Bus calls
+  // and for Property<>. Not permitted with const references to this class.
+  ObjectProxy* object_proxy() { return object_proxy_; }
+
+  // Retrieves the interface of this property set.
+  const std::string& interface() const { return interface_; }
+
+ protected:
+  // Get a weak pointer to this property set, provided so that sub-classes
+  // overriding methods that make D-Bus calls may use the existing (or
+  // override) callbacks without providing their own weak pointer factory.
+  base::WeakPtr<PropertySet> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+ private:
+  // Invalidates properties by reading an array of names, from
+  // |message_reader|. Returns false if message is in incorrect format.
+  bool InvalidatePropertiesFromReader(MessageReader* reader);
+
+  // Pointer to object proxy for making method calls, no ownership is taken
+  // so this must outlive this class.
+  ObjectProxy* object_proxy_;
+
+  // Interface of property, e.g. "org.chromium.ExampleService", this is
+  // distinct from the interface of the method call itself which is the
+  // general D-Bus Properties interface "org.freedesktop.DBus.Properties".
+  std::string interface_;
+
+  // Callback for property changes.
+  PropertyChangedCallback property_changed_callback_;
+
+  // Map of properties (as PropertyBase*) defined in the structure to
+  // names as used in D-Bus method calls and signals. The base pointer
+  // restricts property access via this map to type-unsafe and non-specific
+  // actions only.
+  typedef std::map<const std::string, PropertyBase*> PropertiesMap;
+  PropertiesMap properties_map_;
+
+  // Weak pointer factory as D-Bus callbacks may last longer than these
+  // objects.
+  base::WeakPtrFactory<PropertySet> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PropertySet);
+};
+
+// Property template, this defines the type-specific and type-safe methods
+// of properties that can be accessed as members of a PropertySet structure.
+//
+// Properties provide a cached value that has an initial sensible default
+// until the reply to PropertySet::GetAll() is retrieved and is updated by
+// all calls to that method, PropertySet::Get() and property changed signals
+// also handled by PropertySet. It can be obtained by calling value() on the
+// property.
+//
+// It is recommended that this cached value be used where necessary, with
+// code using PropertySet::PropertyChangedCallback to be notified of changes,
+// rather than incurring a round-trip to the remote object for each property
+// access.
+//
+// Where a round-trip is necessary, the Get() method is provided. And to
+// update the remote object value, the Set() method is also provided; these
+// both simply call methods on PropertySet.
+//
+// Handling of particular D-Bus types is performed via specialization,
+// typically the PopValueFromReader() and AppendSetValueToWriter() methods
+// will need to be provided, and in rare cases a constructor to provide a
+// default value. Specializations for basic D-Bus types, strings, object
+// paths and arrays are provided for you.
+template <class T>
+class CHROME_DBUS_EXPORT Property : public PropertyBase {
+ public:
+  Property() {}
+  ~Property() override {}
+
+  // Retrieves the cached value.
+  const T& value() const { return value_; }
+
+  // Requests an updated value from the remote object incurring a
+  // round-trip. |callback| will be called when the new value is available.
+  // This may not be implemented by some interfaces.
+  virtual void Get(dbus::PropertySet::GetCallback callback) {
+    property_set()->Get(this, callback);
+  }
+
+  // The synchronous version of Get().
+  // This should never be used on an interactive thread.
+  virtual bool GetAndBlock() {
+    return property_set()->GetAndBlock(this);
+  }
+
+  // Requests that the remote object change the property value to |value|,
+  // |callback| will be called to indicate the success or failure of the
+  // request, however the new value may not be available depending on the
+  // remote object.
+  virtual void Set(const T& value, dbus::PropertySet::SetCallback callback) {
+    set_value_ = value;
+    property_set()->Set(this, callback);
+  }
+
+  // The synchronous version of Set().
+  // This should never be used on an interactive thread.
+  virtual bool SetAndBlock(const T& value) {
+    set_value_ = value;
+    return property_set()->SetAndBlock(this);
+  }
+
+  // Method used by PropertySet to retrieve the value from a MessageReader,
+  // no knowledge of the contained type is required, this method returns
+  // true if its expected type was found, false if not.
+  bool PopValueFromReader(MessageReader* reader) override;
+
+  // Method used by PropertySet to append the set value to a MessageWriter,
+  // no knowledge of the contained type is required.
+  // Implementation provided by specialization.
+  void AppendSetValueToWriter(MessageWriter* writer) override;
+
+  // Method used by test and stub implementations of dbus::PropertySet::Set
+  // to replace the property value with the set value without using a
+  // dbus::MessageReader.
+  void ReplaceValueWithSetValue() override {
+    value_ = set_value_;
+    property_set()->NotifyPropertyChanged(name());
+  }
+
+  // Method used by test and stub implementations to directly set the
+  // value of a property.
+  void ReplaceValue(const T& value) {
+    value_ = value;
+    property_set()->NotifyPropertyChanged(name());
+  }
+
+  // Method used by test and stub implementations to directly set the
+  // |set_value_| of a property.
+  void ReplaceSetValueForTesting(const T& value) { set_value_ = value; }
+
+ private:
+  // Current cached value of the property.
+  T value_;
+
+  // Replacement value of the property.
+  T set_value_;
+};
+
+// Clang and GCC don't agree on how attributes should work for explicitly
+// instantiated templates. GCC ignores attributes on explicit instantiations
+// (and emits a warning) while Clang requires the visiblity attribute on the
+// explicit instantiations for them to be visible to other compilation units.
+// Hopefully clang and GCC agree one day, and this can be cleaned up:
+// https://llvm.org/bugs/show_bug.cgi?id=24815
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wattributes"
+
+template <>
+CHROME_DBUS_EXPORT Property<uint8_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint8_t>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<uint8_t>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<uint8_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<bool>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<bool>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<bool>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<bool>;
+
+template <>
+CHROME_DBUS_EXPORT Property<int16_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<int16_t>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<int16_t>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<int16_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<uint16_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint16_t>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<uint16_t>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<uint16_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<int32_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<int32_t>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<int32_t>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<int32_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<uint32_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint32_t>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<uint32_t>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<uint32_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<int64_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<int64_t>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<int64_t>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<int64_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<uint64_t>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<uint64_t>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<uint64_t>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<uint64_t>;
+
+template <>
+CHROME_DBUS_EXPORT Property<double>::Property();
+template <>
+CHROME_DBUS_EXPORT bool Property<double>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<double>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<double>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::string>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<std::string>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::string>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<ObjectPath>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<ObjectPath>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<ObjectPath>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::vector<std::string>>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<
+    std::vector<std::string>>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::vector<std::string>>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::vector<ObjectPath>>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<
+    std::vector<ObjectPath>>::AppendSetValueToWriter(MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::vector<ObjectPath>>;
+
+template <>
+CHROME_DBUS_EXPORT bool Property<std::vector<uint8_t>>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void Property<std::vector<uint8_t>>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT Property<std::vector<uint8_t>>;
+
+template <>
+CHROME_DBUS_EXPORT bool
+Property<std::map<std::string, std::string>>::PopValueFromReader(
+    MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void
+Property<std::map<std::string, std::string>>::AppendSetValueToWriter(
+    MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT
+    Property<std::map<std::string, std::string>>;
+
+template <>
+CHROME_DBUS_EXPORT bool
+Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
+    PopValueFromReader(MessageReader* reader);
+template <>
+CHROME_DBUS_EXPORT void
+Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>::
+    AppendSetValueToWriter(MessageWriter* writer);
+extern template class CHROME_DBUS_EXPORT
+    Property<std::vector<std::pair<std::vector<uint8_t>, uint16_t>>>;
+
+#pragma GCC diagnostic pop
+
+}  // namespace dbus
+
+#endif  // DBUS_PROPERTY_H_
diff --git a/libchrome/dbus/scoped_dbus_error.cc b/libchrome/dbus/scoped_dbus_error.cc
new file mode 100644
index 0000000..fa04971
--- /dev/null
+++ b/libchrome/dbus/scoped_dbus_error.cc
@@ -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.
+
+#include "dbus/scoped_dbus_error.h"
+
+namespace dbus {
+
+ScopedDBusError::ScopedDBusError() {
+  dbus_error_init(&error_);
+}
+
+ScopedDBusError::~ScopedDBusError() {
+  dbus_error_free(&error_);
+}
+
+bool ScopedDBusError::is_set() const {
+  return dbus_error_is_set(&error_);
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/scoped_dbus_error.h b/libchrome/dbus/scoped_dbus_error.h
new file mode 100644
index 0000000..1484dbb
--- /dev/null
+++ b/libchrome/dbus/scoped_dbus_error.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_SCOPED_DBUS_ERROR_H_
+#define DBUS_SCOPED_DBUS_ERROR_H_
+
+#include <dbus/dbus.h>
+
+#include "dbus/dbus_export.h"
+
+namespace dbus {
+
+// Utility class to ensure that DBusError is freed.
+class CHROME_DBUS_EXPORT ScopedDBusError {
+ public:
+  // Do not inline methods that call dbus_error_xxx() functions.
+  // See http://crbug.com/416628
+  ScopedDBusError();
+  ~ScopedDBusError();
+
+  DBusError* get() { return &error_; }
+  bool is_set() const;
+  const char* name() { return error_.name; }
+  const char* message() { return error_.message; }
+
+ private:
+  DBusError error_;
+};
+
+}  // namespace dbus
+
+#endif  // DBUS_SCOPED_DBUS_ERROR_H_
diff --git a/libchrome/dbus/string_util.cc b/libchrome/dbus/string_util.cc
new file mode 100644
index 0000000..7f71015
--- /dev/null
+++ b/libchrome/dbus/string_util.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 "dbus/string_util.h"
+
+#include <stddef.h>
+
+#include "base/strings/string_util.h"
+
+namespace dbus {
+
+// This implementation is based upon D-Bus Specification Version 0.19.
+bool IsValidObjectPath(const std::string& value) {
+  // A valid object path begins with '/'.
+  if (!base::StartsWith(value, "/", base::CompareCase::SENSITIVE))
+    return false;
+
+  // Elements are pieces delimited by '/'. For instance, "org", "chromium",
+  // "Foo" are elements of "/org/chromium/Foo".
+  int element_length = 0;
+  for (size_t i = 1; i < value.size(); ++i) {
+    const char c = value[i];
+    if (c == '/') {
+      // No element may be the empty string.
+      if (element_length == 0)
+        return false;
+      element_length = 0;
+    } else {
+      // Each element must only contain "[A-Z][a-z][0-9]_".
+      const bool is_valid_character =
+          ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') ||
+          ('0' <= c && c <= '9') || c == '_';
+      if (!is_valid_character)
+        return false;
+      element_length++;
+    }
+  }
+
+  // A trailing '/' character is not allowed unless the path is the root path.
+  if (value.size() > 1 &&
+      base::EndsWith(value, "/", base::CompareCase::SENSITIVE))
+    return false;
+
+  return true;
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/string_util.h b/libchrome/dbus/string_util.h
new file mode 100644
index 0000000..60c02d1
--- /dev/null
+++ b/libchrome/dbus/string_util.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_STRING_UTIL_H_
+#define DBUS_STRING_UTIL_H_
+
+#include <string>
+
+#include "dbus/dbus_export.h"
+
+namespace dbus {
+
+// Returns true if the specified string is a valid object path.
+CHROME_DBUS_EXPORT bool IsValidObjectPath(const std::string& value);
+
+}  // namespace dbus
+
+#endif  // DBUS_STRING_UTIL_H_
diff --git a/libchrome/dbus/test_proto.proto b/libchrome/dbus/test_proto.proto
new file mode 100644
index 0000000..1ec128b
--- /dev/null
+++ b/libchrome/dbus/test_proto.proto
@@ -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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+// This is a simple dummy protocol buffer that is used for testing handling of
+// protocol buffers in MessageReader and MessageWriter.
+
+message TestProto {
+    optional string text = 1;
+    optional int32 number = 2;
+}
diff --git a/libchrome/dbus/util.cc b/libchrome/dbus/util.cc
new file mode 100644
index 0000000..26e5c71
--- /dev/null
+++ b/libchrome/dbus/util.cc
@@ -0,0 +1,14 @@
+// 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 "dbus/util.h"
+
+namespace dbus {
+
+std::string GetAbsoluteMemberName(const std::string& interface_name,
+                                  const std::string& member_name) {
+  return interface_name + "." + member_name;
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/util.h b/libchrome/dbus/util.h
new file mode 100644
index 0000000..b05834d
--- /dev/null
+++ b/libchrome/dbus/util.h
@@ -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.
+
+#ifndef DBUS_UTIL_H_
+#define DBUS_UTIL_H_
+
+#include <string>
+
+#include "dbus/dbus_export.h"
+
+namespace dbus {
+
+// Returns the absolute name of a member by concatanating |interface_name| and
+// |member_name|. e.g.:
+//    GetAbsoluteMemberName(
+//        "org.freedesktop.DBus.Properties",
+//        "PropertiesChanged")
+//
+//    => "org.freedesktop.DBus.Properties.PropertiesChanged"
+//
+CHROME_DBUS_EXPORT std::string GetAbsoluteMemberName(
+    const std::string& interface_name,
+    const std::string& member_name);
+
+// Similar to base::DeletePointer, but takes void* as an argument.
+// Used as DBusFreeFunction.
+template<typename T>
+void DeleteVoidPointer(void* memory) {
+  delete static_cast<T*>(memory);
+}
+
+}  // namespace dbus
+
+#endif  // DBUS_UTIL_H_
diff --git a/libchrome/dbus/values_util.cc b/libchrome/dbus/values_util.cc
new file mode 100644
index 0000000..bea7bea
--- /dev/null
+++ b/libchrome/dbus/values_util.cc
@@ -0,0 +1,311 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "dbus/values_util.h"
+
+#include <utility>
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "dbus/message.h"
+
+namespace dbus {
+
+namespace {
+
+// Returns whether |value| is exactly representable by double or not.
+template<typename T>
+bool IsExactlyRepresentableByDouble(T value) {
+  return value == static_cast<T>(static_cast<double>(value));
+}
+
+// Pops values from |reader| and appends them to |list_value|.
+bool PopListElements(MessageReader* reader, base::ListValue* list_value) {
+  while (reader->HasMoreData()) {
+    std::unique_ptr<base::Value> element_value = PopDataAsValue(reader);
+    if (!element_value)
+      return false;
+    list_value->Append(std::move(element_value));
+  }
+  return true;
+}
+
+// Pops dict-entries from |reader| and sets them to |dictionary_value|
+bool PopDictionaryEntries(MessageReader* reader,
+                          base::DictionaryValue* dictionary_value) {
+  while (reader->HasMoreData()) {
+    DCHECK_EQ(Message::DICT_ENTRY, reader->GetDataType());
+    MessageReader entry_reader(NULL);
+    if (!reader->PopDictEntry(&entry_reader))
+      return false;
+    // Get key as a string.
+    std::string key_string;
+    if (entry_reader.GetDataType() == Message::STRING) {
+      // If the type of keys is STRING, pop it directly.
+      if (!entry_reader.PopString(&key_string))
+        return false;
+    } else {
+      // If the type of keys is not STRING, convert it to string.
+      std::unique_ptr<base::Value> key(PopDataAsValue(&entry_reader));
+      if (!key)
+        return false;
+      // Use JSONWriter to convert an arbitrary value to a string.
+      base::JSONWriter::Write(*key, &key_string);
+    }
+    // Get the value and set the key-value pair.
+    std::unique_ptr<base::Value> value = PopDataAsValue(&entry_reader);
+    if (!value)
+      return false;
+    dictionary_value->SetWithoutPathExpansion(key_string, std::move(value));
+  }
+  return true;
+}
+
+// Gets the D-Bus type signature for the value.
+std::string GetTypeSignature(const base::Value& value) {
+  switch (value.GetType()) {
+    case base::Value::TYPE_BOOLEAN:
+      return "b";
+    case base::Value::TYPE_INTEGER:
+      return "i";
+    case base::Value::TYPE_DOUBLE:
+      return "d";
+    case base::Value::TYPE_STRING:
+      return "s";
+    case base::Value::TYPE_BINARY:
+      return "ay";
+    case base::Value::TYPE_DICTIONARY:
+      return "a{sv}";
+    case base::Value::TYPE_LIST:
+      return "av";
+    default:
+      DLOG(ERROR) << "Unexpected type " << value.GetType();
+      return std::string();
+  }
+}
+
+}  // namespace
+
+std::unique_ptr<base::Value> PopDataAsValue(MessageReader* reader) {
+  std::unique_ptr<base::Value> result;
+  switch (reader->GetDataType()) {
+    case Message::INVALID_DATA:
+      // Do nothing.
+      break;
+    case Message::BYTE: {
+      uint8_t value = 0;
+      if (reader->PopByte(&value))
+        result = base::MakeUnique<base::FundamentalValue>(value);
+      break;
+    }
+    case Message::BOOL: {
+      bool value = false;
+      if (reader->PopBool(&value))
+        result = base::MakeUnique<base::FundamentalValue>(value);
+      break;
+    }
+    case Message::INT16: {
+      int16_t value = 0;
+      if (reader->PopInt16(&value))
+        result = base::MakeUnique<base::FundamentalValue>(value);
+      break;
+    }
+    case Message::UINT16: {
+      uint16_t value = 0;
+      if (reader->PopUint16(&value))
+        result = base::MakeUnique<base::FundamentalValue>(value);
+      break;
+    }
+    case Message::INT32: {
+      int32_t value = 0;
+      if (reader->PopInt32(&value))
+        result = base::MakeUnique<base::FundamentalValue>(value);
+      break;
+    }
+    case Message::UINT32: {
+      uint32_t value = 0;
+      if (reader->PopUint32(&value)) {
+        result = base::MakeUnique<base::FundamentalValue>(
+            static_cast<double>(value));
+      }
+      break;
+    }
+    case Message::INT64: {
+      int64_t value = 0;
+      if (reader->PopInt64(&value)) {
+        DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
+            value << " is not exactly representable by double";
+        result = base::MakeUnique<base::FundamentalValue>(
+            static_cast<double>(value));
+      }
+      break;
+    }
+    case Message::UINT64: {
+      uint64_t value = 0;
+      if (reader->PopUint64(&value)) {
+        DLOG_IF(WARNING, !IsExactlyRepresentableByDouble(value)) <<
+            value << " is not exactly representable by double";
+        result = base::MakeUnique<base::FundamentalValue>(
+            static_cast<double>(value));
+      }
+      break;
+    }
+    case Message::DOUBLE: {
+      double value = 0;
+      if (reader->PopDouble(&value))
+        result = base::MakeUnique<base::FundamentalValue>(value);
+      break;
+    }
+    case Message::STRING: {
+      std::string value;
+      if (reader->PopString(&value))
+        result = base::MakeUnique<base::StringValue>(value);
+      break;
+    }
+    case Message::OBJECT_PATH: {
+      ObjectPath value;
+      if (reader->PopObjectPath(&value))
+        result = base::MakeUnique<base::StringValue>(value.value());
+      break;
+    }
+    case Message::UNIX_FD: {
+      // Cannot distinguish a file descriptor from an int
+      NOTREACHED();
+      break;
+    }
+    case Message::ARRAY: {
+      MessageReader sub_reader(NULL);
+      if (reader->PopArray(&sub_reader)) {
+        // If the type of the array's element is DICT_ENTRY, create a
+        // DictionaryValue, otherwise create a ListValue.
+        if (sub_reader.GetDataType() == Message::DICT_ENTRY) {
+          std::unique_ptr<base::DictionaryValue> dictionary_value(
+              new base::DictionaryValue);
+          if (PopDictionaryEntries(&sub_reader, dictionary_value.get()))
+            result = std::move(dictionary_value);
+        } else {
+          std::unique_ptr<base::ListValue> list_value(new base::ListValue);
+          if (PopListElements(&sub_reader, list_value.get()))
+            result = std::move(list_value);
+        }
+      }
+      break;
+    }
+    case Message::STRUCT: {
+      MessageReader sub_reader(NULL);
+      if (reader->PopStruct(&sub_reader)) {
+        std::unique_ptr<base::ListValue> list_value(new base::ListValue);
+        if (PopListElements(&sub_reader, list_value.get()))
+          result = std::move(list_value);
+      }
+      break;
+    }
+    case Message::DICT_ENTRY:
+      // DICT_ENTRY must be popped as an element of an array.
+      NOTREACHED();
+      break;
+    case Message::VARIANT: {
+      MessageReader sub_reader(NULL);
+      if (reader->PopVariant(&sub_reader))
+        result = PopDataAsValue(&sub_reader);
+      break;
+    }
+  }
+  return result;
+}
+
+void AppendBasicTypeValueData(MessageWriter* writer, const base::Value& value) {
+  switch (value.GetType()) {
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value = false;
+      bool success = value.GetAsBoolean(&bool_value);
+      DCHECK(success);
+      writer->AppendBool(bool_value);
+      break;
+    }
+    case base::Value::TYPE_INTEGER: {
+      int int_value = 0;
+      bool success = value.GetAsInteger(&int_value);
+      DCHECK(success);
+      writer->AppendInt32(int_value);
+      break;
+    }
+    case base::Value::TYPE_DOUBLE: {
+      double double_value = 0;
+      bool success = value.GetAsDouble(&double_value);
+      DCHECK(success);
+      writer->AppendDouble(double_value);
+      break;
+    }
+    case base::Value::TYPE_STRING: {
+      std::string string_value;
+      bool success = value.GetAsString(&string_value);
+      DCHECK(success);
+      writer->AppendString(string_value);
+      break;
+    }
+    default:
+      DLOG(ERROR) << "Unexpected type " << value.GetType();
+      break;
+  }
+}
+
+void AppendBasicTypeValueDataAsVariant(MessageWriter* writer,
+                                       const base::Value& value) {
+  MessageWriter sub_writer(NULL);
+  writer->OpenVariant(GetTypeSignature(value), &sub_writer);
+  AppendBasicTypeValueData(&sub_writer, value);
+  writer->CloseContainer(&sub_writer);
+}
+
+void AppendValueData(MessageWriter* writer, const base::Value& value) {
+  switch (value.GetType()) {
+    case base::Value::TYPE_DICTIONARY: {
+      const base::DictionaryValue* dictionary = NULL;
+      value.GetAsDictionary(&dictionary);
+      dbus::MessageWriter array_writer(NULL);
+      writer->OpenArray("{sv}", &array_writer);
+      for (base::DictionaryValue::Iterator iter(*dictionary);
+           !iter.IsAtEnd(); iter.Advance()) {
+        dbus::MessageWriter dict_entry_writer(NULL);
+        array_writer.OpenDictEntry(&dict_entry_writer);
+        dict_entry_writer.AppendString(iter.key());
+        AppendValueDataAsVariant(&dict_entry_writer, iter.value());
+        array_writer.CloseContainer(&dict_entry_writer);
+      }
+      writer->CloseContainer(&array_writer);
+      break;
+    }
+    case base::Value::TYPE_LIST: {
+      const base::ListValue* list = NULL;
+      value.GetAsList(&list);
+      dbus::MessageWriter array_writer(NULL);
+      writer->OpenArray("v", &array_writer);
+      for (const auto& value : *list) {
+        AppendValueDataAsVariant(&array_writer, *value);
+      }
+      writer->CloseContainer(&array_writer);
+      break;
+    }
+    case base::Value::TYPE_BOOLEAN:
+    case base::Value::TYPE_INTEGER:
+    case base::Value::TYPE_DOUBLE:
+    case base::Value::TYPE_STRING:
+      AppendBasicTypeValueData(writer, value);
+      break;
+    default:
+      DLOG(ERROR) << "Unexpected type: " << value.GetType();
+  }
+}
+
+void AppendValueDataAsVariant(MessageWriter* writer, const base::Value& value) {
+  MessageWriter variant_writer(NULL);
+  writer->OpenVariant(GetTypeSignature(value), &variant_writer);
+  AppendValueData(&variant_writer, value);
+  writer->CloseContainer(&variant_writer);
+}
+
+}  // namespace dbus
diff --git a/libchrome/dbus/values_util.h b/libchrome/dbus/values_util.h
new file mode 100644
index 0000000..81b839b
--- /dev/null
+++ b/libchrome/dbus/values_util.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 DBUS_VALUES_UTIL_H_
+#define DBUS_VALUES_UTIL_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "dbus/dbus_export.h"
+
+namespace base {
+class Value;
+}
+
+namespace dbus {
+
+class MessageReader;
+class MessageWriter;
+
+// Pops a value from |reader| as a base::Value.
+// Returns NULL if an error occurs.
+// Note: Integer values larger than int32_t (including uint32_t) are converted
+// to double.  Non-string dictionary keys are converted to strings.
+CHROME_DBUS_EXPORT std::unique_ptr<base::Value> PopDataAsValue(
+    MessageReader* reader);
+
+// Appends a basic type value to |writer|. Basic types are BOOLEAN, INTEGER,
+// DOUBLE, and STRING. Use this function for values that are known to be basic
+// types and to handle basic type members of collections that should not
+// have type "a{sv}" or "av". Otherwise, use AppendValueData.
+CHROME_DBUS_EXPORT void AppendBasicTypeValueData(MessageWriter* writer,
+                                                 const base::Value& value);
+
+// Appends a basic type value to |writer| as a variant. Basic types are BOOLEAN,
+// INTEGER, DOUBLE, and STRING. Use this function for values that are known to
+// be basic types and to handle basic type members of collections that should
+// not have type "a{sv}" or "av". Otherwise, use AppendValueDataAsVariant.
+CHROME_DBUS_EXPORT void AppendBasicTypeValueDataAsVariant(
+    MessageWriter* writer,
+    const base::Value& value);
+
+// Appends a value to |writer|. Value can be a basic type, as well as a
+// collection type, such as dictionary or list. Collections will be recursively
+// written as variant containers, i.e. dictionaries will be written with type
+// a{sv} and lists with type av. Any sub-dictionaries or sub-lists will also
+// have these types.
+CHROME_DBUS_EXPORT void AppendValueData(MessageWriter* writer,
+                                        const base::Value& value);
+
+// Appends a value to |writer| as a variant. Value can be a basic type, as well
+// as a collection type, such as dictionary or list. Collections will be
+// recursively written as variant containers, i.e. dictionaries will be written
+// with type a{sv} and lists with type av. Any sub-dictionaries or sub-lists
+// will also have these types.
+CHROME_DBUS_EXPORT void AppendValueDataAsVariant(MessageWriter* writer,
+                                                 const base::Value& value);
+
+}  // namespace dbus
+
+#endif  // DBUS_VALUES_UTIL_H_
diff --git a/libchrome/sandbox/BUILD.gn b/libchrome/sandbox/BUILD.gn
new file mode 100644
index 0000000..8ca3574
--- /dev/null
+++ b/libchrome/sandbox/BUILD.gn
@@ -0,0 +1,21 @@
+# 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.
+
+# Meta-target that forwards to the proper platform one.
+group("sandbox") {
+  if (is_win) {
+    public_deps = [
+      "//sandbox/win:sandbox",
+    ]
+  } else if (is_mac) {
+    public_deps = [
+      "//sandbox/mac:sandbox",
+      "//sandbox/mac:seatbelt",
+    ]
+  } else if (is_linux || is_android) {
+    public_deps = [
+      "//sandbox/linux:sandbox",
+    ]
+  }
+}
diff --git a/libchrome/sandbox/OWNERS b/libchrome/sandbox/OWNERS
new file mode 100644
index 0000000..5d3f6ff
--- /dev/null
+++ b/libchrome/sandbox/OWNERS
@@ -0,0 +1,3 @@
+cpu@chromium.org
+jln@chromium.org
+jschuh@chromium.org
diff --git a/libchrome/sandbox/linux/BUILD.gn b/libchrome/sandbox/linux/BUILD.gn
new file mode 100644
index 0000000..a5c041f
--- /dev/null
+++ b/libchrome/sandbox/linux/BUILD.gn
@@ -0,0 +1,461 @@
+# 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/features.gni")
+import("//build/config/nacl/config.gni")
+import("//testing/test.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+declare_args() {
+  compile_suid_client = is_linux
+
+  compile_credentials = is_linux
+
+  # On Android, use plain GTest.
+  use_base_test_suite = is_linux
+}
+
+if (is_nacl_nonsfi) {
+  config("nacl_nonsfi_warnings") {
+    # There are number of platform specific functions in
+    # seccomp-bpf syscall helpers, which are not being used.
+    cflags = [ "-Wno-unused-function" ]
+  }
+}
+
+# We have two principal targets: sandbox and sandbox_linux_unittests
+# All other targets are listed as dependencies.
+# There is one notable exception: for historical reasons, chrome_sandbox is
+# the setuid sandbox and is its own target.
+
+group("sandbox") {
+  public_deps = [
+    ":sandbox_services",
+  ]
+
+  if (compile_suid_client || is_nacl_nonsfi) {
+    public_deps += [ ":suid_sandbox_client" ]
+  }
+  if (use_seccomp_bpf || is_nacl_nonsfi) {
+    public_deps += [
+      ":seccomp_bpf",
+      ":seccomp_bpf_helpers",
+    ]
+  }
+}
+
+source_set("sandbox_linux_test_utils") {
+  testonly = true
+  sources = [
+    "tests/sandbox_test_runner.cc",
+    "tests/sandbox_test_runner.h",
+    "tests/sandbox_test_runner_function_pointer.cc",
+    "tests/sandbox_test_runner_function_pointer.h",
+    "tests/unit_tests.cc",
+    "tests/unit_tests.h",
+  ]
+
+  deps = [
+    "//testing/gtest",
+  ]
+
+  if (!is_nacl_nonsfi) {
+    sources += [
+      "tests/test_utils.cc",
+      "tests/test_utils.h",
+    ]
+  }
+
+  if (use_seccomp_bpf || is_nacl_nonsfi) {
+    sources += [
+      "seccomp-bpf/bpf_tester_compatibility_delegate.h",
+      "seccomp-bpf/bpf_tests.h",
+      "seccomp-bpf/sandbox_bpf_test_runner.cc",
+      "seccomp-bpf/sandbox_bpf_test_runner.h",
+    ]
+    deps += [ ":seccomp_bpf" ]
+  }
+
+  if (use_base_test_suite) {
+    deps += [ "//base/test:test_support" ]
+    defines = [ "SANDBOX_USES_BASE_TEST_SUITE" ]
+  }
+}
+
+# Sources for sandbox_linux_unittests.
+source_set("sandbox_linux_unittests_sources") {
+  testonly = true
+
+  sources = [
+    "services/proc_util_unittest.cc",
+    "services/resource_limits_unittests.cc",
+    "services/scoped_process_unittest.cc",
+    "services/syscall_wrappers_unittest.cc",
+    "services/thread_helpers_unittests.cc",
+    "services/yama_unittests.cc",
+    "syscall_broker/broker_file_permission_unittest.cc",
+    "syscall_broker/broker_process_unittest.cc",
+    "tests/main.cc",
+    "tests/scoped_temporary_file.cc",
+    "tests/scoped_temporary_file.h",
+    "tests/scoped_temporary_file_unittest.cc",
+    "tests/test_utils_unittest.cc",
+    "tests/unit_tests_unittest.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    ":sandbox_linux_test_utils",
+    "//base",
+    "//testing/gtest",
+  ]
+
+  if (use_base_test_suite) {
+    deps += [ "//base/test:test_support" ]
+    defines = [ "SANDBOX_USES_BASE_TEST_SUITE" ]
+  }
+
+  if (compile_suid_client) {
+    sources += [
+      "suid/client/setuid_sandbox_client_unittest.cc",
+      "suid/client/setuid_sandbox_host_unittest.cc",
+    ]
+  }
+  if (use_seccomp_bpf) {
+    sources += [
+      "bpf_dsl/bpf_dsl_unittest.cc",
+      "bpf_dsl/codegen_unittest.cc",
+      "bpf_dsl/cons_unittest.cc",
+      "bpf_dsl/dump_bpf.cc",
+      "bpf_dsl/dump_bpf.h",
+      "bpf_dsl/syscall_set_unittest.cc",
+      "bpf_dsl/test_trap_registry.cc",
+      "bpf_dsl/test_trap_registry.h",
+      "bpf_dsl/test_trap_registry_unittest.cc",
+      "bpf_dsl/verifier.cc",
+      "bpf_dsl/verifier.h",
+      "integration_tests/bpf_dsl_seccomp_unittest.cc",
+      "integration_tests/seccomp_broker_process_unittest.cc",
+      "seccomp-bpf-helpers/baseline_policy_unittest.cc",
+      "seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc",
+      "seccomp-bpf/bpf_tests_unittest.cc",
+      "seccomp-bpf/sandbox_bpf_unittest.cc",
+      "seccomp-bpf/syscall_unittest.cc",
+      "seccomp-bpf/trap_unittest.cc",
+    ]
+    deps += [ ":bpf_dsl_golden" ]
+  }
+  if (compile_credentials) {
+    sources += [
+      "integration_tests/namespace_unix_domain_socket_unittest.cc",
+      "services/credentials_unittest.cc",
+      "services/namespace_utils_unittest.cc",
+    ]
+
+    if (use_base_test_suite) {
+      # Tests that use advanced features not available in stock GTest.
+      sources += [ "services/namespace_sandbox_unittest.cc" ]
+    }
+
+    # For credentials_unittest.cc
+    configs += [ "//build/config/linux:libcap" ]
+  }
+}
+
+action("bpf_dsl_golden") {
+  script = "bpf_dsl/golden/generate.py"
+  inputs = [
+    "bpf_dsl/golden/i386/ArgSizePolicy.txt",
+    "bpf_dsl/golden/i386/BasicPolicy.txt",
+    "bpf_dsl/golden/i386/ElseIfPolicy.txt",
+    "bpf_dsl/golden/i386/MaskingPolicy.txt",
+    "bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt",
+    "bpf_dsl/golden/i386/NegativeConstantsPolicy.txt",
+    "bpf_dsl/golden/i386/SwitchPolicy.txt",
+    "bpf_dsl/golden/x86-64/ArgSizePolicy.txt",
+    "bpf_dsl/golden/x86-64/BasicPolicy.txt",
+    "bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt",
+    "bpf_dsl/golden/x86-64/ElseIfPolicy.txt",
+    "bpf_dsl/golden/x86-64/MaskingPolicy.txt",
+    "bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt",
+    "bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt",
+    "bpf_dsl/golden/x86-64/SwitchPolicy.txt",
+  ]
+  outputs = [
+    "$target_gen_dir/bpf_dsl/golden/golden_files.h",
+  ]
+  args =
+      rebase_path(outputs, root_build_dir) + rebase_path(inputs, root_build_dir)
+}
+
+
+test("sandbox_linux_unittests") {
+  deps = [
+    ":sandbox_linux_unittests_sources",
+    "//build/config/sanitizers:deps",
+  ]
+  if (is_android) {
+    use_raw_android_executable = true
+  }
+}
+
+component("seccomp_bpf") {
+  sources = [
+    "bpf_dsl/bpf_dsl.cc",
+    "bpf_dsl/bpf_dsl.h",
+    "bpf_dsl/bpf_dsl_forward.h",
+    "bpf_dsl/bpf_dsl_impl.h",
+    "bpf_dsl/codegen.cc",
+    "bpf_dsl/codegen.h",
+    "bpf_dsl/cons.h",
+    "bpf_dsl/errorcode.h",
+    "bpf_dsl/linux_syscall_ranges.h",
+    "bpf_dsl/policy.cc",
+    "bpf_dsl/policy.h",
+    "bpf_dsl/policy_compiler.cc",
+    "bpf_dsl/policy_compiler.h",
+    "bpf_dsl/seccomp_macros.h",
+    "bpf_dsl/syscall_set.cc",
+    "bpf_dsl/syscall_set.h",
+    "bpf_dsl/trap_registry.h",
+    "seccomp-bpf/die.cc",
+    "seccomp-bpf/die.h",
+    "seccomp-bpf/sandbox_bpf.cc",
+    "seccomp-bpf/sandbox_bpf.h",
+    "seccomp-bpf/syscall.cc",
+    "seccomp-bpf/syscall.h",
+    "seccomp-bpf/trap.cc",
+    "seccomp-bpf/trap.h",
+  ]
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+  public_deps = [
+    ":sandbox_services_headers",
+  ]
+  deps = [
+    ":sandbox_services",
+    "//base",
+  ]
+
+  if (is_nacl_nonsfi) {
+    cflags = [ "-fgnu-inline-asm" ]
+    sources -= [
+      "bpf_dsl/bpf_dsl_forward.h",
+      "bpf_dsl/bpf_dsl_impl.h",
+      "bpf_dsl/cons.h",
+      "bpf_dsl/errorcode.h",
+      "bpf_dsl/linux_syscall_ranges.h",
+      "bpf_dsl/seccomp_macros.h",
+      "bpf_dsl/trap_registry.h",
+    ]
+  }
+}
+
+component("seccomp_bpf_helpers") {
+  sources = [
+    "seccomp-bpf-helpers/baseline_policy.cc",
+    "seccomp-bpf-helpers/baseline_policy.h",
+    "seccomp-bpf-helpers/sigsys_handlers.cc",
+    "seccomp-bpf-helpers/sigsys_handlers.h",
+    "seccomp-bpf-helpers/syscall_parameters_restrictions.cc",
+    "seccomp-bpf-helpers/syscall_parameters_restrictions.h",
+    "seccomp-bpf-helpers/syscall_sets.cc",
+    "seccomp-bpf-helpers/syscall_sets.h",
+  ]
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+  deps = [
+    ":sandbox_services",
+    ":seccomp_bpf",
+    "//base",
+  ]
+
+  if (is_nacl_nonsfi) {
+    sources -= [
+      "seccomp-bpf-helpers/baseline_policy.cc",
+      "seccomp-bpf-helpers/baseline_policy.h",
+      "seccomp-bpf-helpers/syscall_sets.cc",
+      "seccomp-bpf-helpers/syscall_sets.h",
+    ]
+    configs += [ ":nacl_nonsfi_warnings" ]
+  }
+}
+
+if (is_linux) {
+  # The setuid sandbox for Linux.
+  executable("chrome_sandbox") {
+    sources = [
+      "suid/common/sandbox.h",
+      "suid/common/suid_unsafe_environment_variables.h",
+      "suid/process_util.h",
+      "suid/process_util_linux.c",
+      "suid/sandbox.c",
+    ]
+
+    cflags = [
+      # For ULLONG_MAX
+      "-std=gnu99",
+
+      # These files have a suspicious comparison.
+      # TODO fix this and re-enable this warning.
+      "-Wno-sign-compare",
+    ]
+
+    import("//build/config/compiler/compiler.gni")
+    import("//build/config/sanitizers/sanitizers.gni")
+    if (is_component_build || using_sanitizer) {
+      # WARNING! We remove this config so that we don't accidentally
+      # pick up the //build/config:rpath_for_built_shared_libraries
+      # sub-config. However, this means that we need to duplicate any
+      # other flags that executable_config might have.
+      configs -= [ "//build/config:executable_config" ]
+      if (!use_gold) {
+        ldflags = [ "-Wl,--disable-new-dtags" ]
+      }
+    }
+
+    # We also do not want to pick up any of the other sanitizer
+    # flags (i.e. we do not want to build w/ the sanitizers at all).
+    # This is safe to delete unconditionally, because it is part of the
+    # default configs and empty when not using the sanitizers.
+    configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ]
+  }
+}
+
+component("sandbox_services") {
+  sources = [
+    "services/init_process_reaper.cc",
+    "services/init_process_reaper.h",
+    "services/proc_util.cc",
+    "services/proc_util.h",
+    "services/resource_limits.cc",
+    "services/resource_limits.h",
+    "services/scoped_process.cc",
+    "services/scoped_process.h",
+    "services/syscall_wrappers.cc",
+    "services/syscall_wrappers.h",
+    "services/thread_helpers.cc",
+    "services/thread_helpers.h",
+    "services/yama.cc",
+    "services/yama.h",
+    "syscall_broker/broker_channel.cc",
+    "syscall_broker/broker_channel.h",
+    "syscall_broker/broker_client.cc",
+    "syscall_broker/broker_client.h",
+    "syscall_broker/broker_common.h",
+    "syscall_broker/broker_file_permission.cc",
+    "syscall_broker/broker_file_permission.h",
+    "syscall_broker/broker_host.cc",
+    "syscall_broker/broker_host.h",
+    "syscall_broker/broker_policy.cc",
+    "syscall_broker/broker_policy.h",
+    "syscall_broker/broker_process.cc",
+    "syscall_broker/broker_process.h",
+  ]
+
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+  public_deps = []
+  deps = [
+    "//base",
+  ]
+
+  if (compile_credentials || is_nacl_nonsfi) {
+    sources += [
+      "services/credentials.cc",
+      "services/credentials.h",
+      "services/namespace_sandbox.cc",
+      "services/namespace_sandbox.h",
+      "services/namespace_utils.cc",
+      "services/namespace_utils.h",
+    ]
+
+    public_deps += [ ":sandbox_services_headers" ]
+  }
+
+  if (is_nacl_nonsfi) {
+    cflags = [ "-fgnu-inline-asm" ]
+
+    sources -= [
+      "services/init_process_reaper.cc",
+      "services/init_process_reaper.h",
+      "services/scoped_process.cc",
+      "services/scoped_process.h",
+      "services/yama.cc",
+      "services/yama.h",
+      "syscall_broker/broker_channel.cc",
+      "syscall_broker/broker_channel.h",
+      "syscall_broker/broker_client.cc",
+      "syscall_broker/broker_client.h",
+      "syscall_broker/broker_common.h",
+      "syscall_broker/broker_file_permission.cc",
+      "syscall_broker/broker_file_permission.h",
+      "syscall_broker/broker_host.cc",
+      "syscall_broker/broker_host.h",
+      "syscall_broker/broker_policy.cc",
+      "syscall_broker/broker_policy.h",
+      "syscall_broker/broker_process.cc",
+      "syscall_broker/broker_process.h",
+    ]
+  }
+}
+
+source_set("sandbox_services_headers") {
+  sources = [
+    "system_headers/arm64_linux_syscalls.h",
+    "system_headers/arm64_linux_ucontext.h",
+    "system_headers/arm_linux_syscalls.h",
+    "system_headers/arm_linux_ucontext.h",
+    "system_headers/i386_linux_ucontext.h",
+    "system_headers/linux_futex.h",
+    "system_headers/linux_seccomp.h",
+    "system_headers/linux_signal.h",
+    "system_headers/linux_syscalls.h",
+    "system_headers/linux_time.h",
+    "system_headers/linux_ucontext.h",
+    "system_headers/x86_32_linux_syscalls.h",
+    "system_headers/x86_64_linux_syscalls.h",
+  ]
+}
+
+if (compile_suid_client || is_nacl_nonsfi) {
+  component("suid_sandbox_client") {
+    sources = [
+      "suid/client/setuid_sandbox_client.cc",
+      "suid/client/setuid_sandbox_client.h",
+      "suid/client/setuid_sandbox_host.cc",
+      "suid/client/setuid_sandbox_host.h",
+      "suid/common/sandbox.h",
+      "suid/common/suid_unsafe_environment_variables.h",
+    ]
+    defines = [ "SANDBOX_IMPLEMENTATION" ]
+
+    deps = [
+      ":sandbox_services",
+      "//base",
+    ]
+
+    if (is_nacl_nonsfi) {
+      sources -= [
+        "suid/client/setuid_sandbox_host.cc",
+        "suid/client/setuid_sandbox_host.h",
+        "suid/common/sandbox.h",
+        "suid/common/suid_unsafe_environment_variables.h",
+      ]
+    }
+  }
+}
+
+if (is_android) {
+  # TODO(GYP_GONE) Delete this after we've converted everything to GN.
+  group("sandbox_linux_unittests_deps") {
+    testonly = true
+    deps = [
+      ":sandbox_linux_unittests",
+    ]
+  }
+}
diff --git a/libchrome/sandbox/linux/DEPS b/libchrome/sandbox/linux/DEPS
new file mode 100644
index 0000000..3912859
--- /dev/null
+++ b/libchrome/sandbox/linux/DEPS
@@ -0,0 +1,25 @@
+include_rules = [
+  # First, exclude everything.
+  # Exclude a few dependencies that are included in the root DEPS and that we
+  # don't need.
+  # Sadly, there is no way to exclude all root DEPS since the root has no name.
+  "-ipc",
+  "-library_loaders",
+  "-third_party",
+  "-url",
+  # Make sure that each subdirectory has to declare its dependencies in
+  # sandbox/ explicitly.
+  "-sandbox/linux",
+
+  # Second, add what we want to allow.
+  # Anything included from sandbox/linux must be declared after this line or in
+  # a more specific DEPS file.
+  # base/, build/ and testing/ are already included in the global DEPS file,
+  # but be explicit.
+  "+base",
+  "+build",
+  "+testing",
+  "+sandbox/sandbox_export.h",
+  # Everyone can use tests/
+  "+sandbox/linux/tests",
+]
diff --git a/libchrome/sandbox/linux/OWNERS b/libchrome/sandbox/linux/OWNERS
new file mode 100644
index 0000000..99ef1bd
--- /dev/null
+++ b/libchrome/sandbox/linux/OWNERS
@@ -0,0 +1,4 @@
+jln@chromium.org
+jorgelo@chromium.org
+mdempsky@chromium.org
+rickyz@chromium.org
diff --git a/libchrome/sandbox/linux/bpf_dsl/DEPS b/libchrome/sandbox/linux/bpf_dsl/DEPS
new file mode 100644
index 0000000..70d9b18
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox/linux/system_headers",
+]
diff --git a/libchrome/sandbox/linux/bpf_dsl/bpf_dsl.cc b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl.cc
new file mode 100644
index 0000000..fed6368
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl.cc
@@ -0,0 +1,343 @@
+// 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 "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/errorcode.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace {
+
+class ReturnResultExprImpl : public internal::ResultExprImpl {
+ public:
+  explicit ReturnResultExprImpl(uint32_t ret) : ret_(ret) {}
+  ~ReturnResultExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc) const override {
+    return pc->Return(ret_);
+  }
+
+  bool IsAllow() const override { return IsAction(SECCOMP_RET_ALLOW); }
+
+  bool IsDeny() const override {
+    return IsAction(SECCOMP_RET_ERRNO) || IsAction(SECCOMP_RET_KILL);
+  }
+
+ private:
+  bool IsAction(uint32_t action) const {
+    return (ret_ & SECCOMP_RET_ACTION) == action;
+  }
+
+  uint32_t ret_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReturnResultExprImpl);
+};
+
+class TrapResultExprImpl : public internal::ResultExprImpl {
+ public:
+  TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg, bool safe)
+      : func_(func), arg_(arg), safe_(safe) {
+    DCHECK(func_);
+  }
+  ~TrapResultExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc) const override {
+    return pc->Trap(func_, arg_, safe_);
+  }
+
+  bool HasUnsafeTraps() const override { return safe_ == false; }
+
+  bool IsDeny() const override { return true; }
+
+ private:
+  TrapRegistry::TrapFnc func_;
+  const void* arg_;
+  bool safe_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl);
+};
+
+class IfThenResultExprImpl : public internal::ResultExprImpl {
+ public:
+  IfThenResultExprImpl(BoolExpr cond,
+                       ResultExpr then_result,
+                       ResultExpr else_result)
+      : cond_(std::move(cond)),
+        then_result_(std::move(then_result)),
+        else_result_(std::move(else_result)) {}
+  ~IfThenResultExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc) const override {
+    // We compile the "then" and "else" expressions in separate statements so
+    // they have a defined sequencing.  See https://crbug.com/529480.
+    CodeGen::Node then_node = then_result_->Compile(pc);
+    CodeGen::Node else_node = else_result_->Compile(pc);
+    return cond_->Compile(pc, then_node, else_node);
+  }
+
+  bool HasUnsafeTraps() const override {
+    return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps();
+  }
+
+ private:
+  BoolExpr cond_;
+  ResultExpr then_result_;
+  ResultExpr else_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl);
+};
+
+class ConstBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  ConstBoolExprImpl(bool value) : value_(value) {}
+  ~ConstBoolExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return value_ ? then_node : else_node;
+  }
+
+ private:
+  bool value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
+};
+
+class MaskedEqualBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  MaskedEqualBoolExprImpl(int argno,
+                          size_t width,
+                          uint64_t mask,
+                          uint64_t value)
+      : argno_(argno), width_(width), mask_(mask), value_(value) {}
+  ~MaskedEqualBoolExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return pc->MaskedEqual(argno_, width_, mask_, value_, then_node, else_node);
+  }
+
+ private:
+  int argno_;
+  size_t width_;
+  uint64_t mask_;
+  uint64_t value_;
+
+  DISALLOW_COPY_AND_ASSIGN(MaskedEqualBoolExprImpl);
+};
+
+class NegateBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  explicit NegateBoolExprImpl(BoolExpr cond) : cond_(std::move(cond)) {}
+  ~NegateBoolExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return cond_->Compile(pc, else_node, then_node);
+  }
+
+ private:
+  BoolExpr cond_;
+
+  DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl);
+};
+
+class AndBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  AndBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
+      : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+  ~AndBoolExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return lhs_->Compile(pc, rhs_->Compile(pc, then_node, else_node),
+                         else_node);
+  }
+
+ private:
+  BoolExpr lhs_;
+  BoolExpr rhs_;
+
+  DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl);
+};
+
+class OrBoolExprImpl : public internal::BoolExprImpl {
+ public:
+  OrBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
+      : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+  ~OrBoolExprImpl() override {}
+
+  CodeGen::Node Compile(PolicyCompiler* pc,
+                        CodeGen::Node then_node,
+                        CodeGen::Node else_node) const override {
+    return lhs_->Compile(pc, then_node,
+                         rhs_->Compile(pc, then_node, else_node));
+  }
+
+ private:
+  BoolExpr lhs_;
+  BoolExpr rhs_;
+
+  DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl);
+};
+
+}  // namespace
+
+namespace internal {
+
+bool ResultExprImpl::HasUnsafeTraps() const {
+  return false;
+}
+
+bool ResultExprImpl::IsAllow() const {
+  return false;
+}
+
+bool ResultExprImpl::IsDeny() const {
+  return false;
+}
+
+uint64_t DefaultMask(size_t size) {
+  switch (size) {
+    case 4:
+      return std::numeric_limits<uint32_t>::max();
+    case 8:
+      return std::numeric_limits<uint64_t>::max();
+    default:
+      CHECK(false) << "Unimplemented DefaultMask case";
+      return 0;
+  }
+}
+
+BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) {
+  // If this is changed, update Arg<T>::EqualTo's static_cast rules
+  // accordingly.
+  CHECK(size == 4 || size == 8);
+
+  return std::make_shared<MaskedEqualBoolExprImpl>(num, size, mask, val);
+}
+
+}  // namespace internal
+
+ResultExpr Allow() {
+  return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ALLOW);
+}
+
+ResultExpr Error(int err) {
+  CHECK(err >= ErrorCode::ERR_MIN_ERRNO && err <= ErrorCode::ERR_MAX_ERRNO);
+  return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ERRNO + err);
+}
+
+ResultExpr Kill() {
+  return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_KILL);
+}
+
+ResultExpr Trace(uint16_t aux) {
+  return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_TRACE + aux);
+}
+
+ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+  return std::make_shared<TrapResultExprImpl>(trap_func, aux, true /* safe */);
+}
+
+ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+  return std::make_shared<TrapResultExprImpl>(trap_func, aux,
+                                              false /* unsafe */);
+}
+
+BoolExpr BoolConst(bool value) {
+  return std::make_shared<ConstBoolExprImpl>(value);
+}
+
+BoolExpr Not(BoolExpr cond) {
+  return std::make_shared<NegateBoolExprImpl>(std::move(cond));
+}
+
+BoolExpr AllOf() {
+  return BoolConst(true);
+}
+
+BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs) {
+  return std::make_shared<AndBoolExprImpl>(std::move(lhs), std::move(rhs));
+}
+
+BoolExpr AnyOf() {
+  return BoolConst(false);
+}
+
+BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs) {
+  return std::make_shared<OrBoolExprImpl>(std::move(lhs), std::move(rhs));
+}
+
+Elser If(BoolExpr cond, ResultExpr then_result) {
+  return Elser(nullptr).ElseIf(std::move(cond), std::move(then_result));
+}
+
+Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
+}
+
+Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
+}
+
+Elser::~Elser() {
+}
+
+Elser Elser::ElseIf(BoolExpr cond, ResultExpr then_result) const {
+  return Elser(Cons(std::make_pair(std::move(cond), std::move(then_result)),
+                    clause_list_));
+}
+
+ResultExpr Elser::Else(ResultExpr else_result) const {
+  // We finally have the default result expression for this
+  // if/then/else sequence.  Also, we've already accumulated all
+  // if/then pairs into a list of reverse order (i.e., lower priority
+  // conditions are listed before higher priority ones).  E.g., an
+  // expression like
+  //
+  //    If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4)
+  //
+  // will have built up a list like
+  //
+  //    [(b3, e3), (b2, e2), (b1, e1)].
+  //
+  // Now that we have e4, we can walk the list and create a ResultExpr
+  // tree like:
+  //
+  //    expr = e4
+  //    expr = (b3 ? e3 : expr) = (b3 ? e3 : e4)
+  //    expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4))
+  //    expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4)))
+  //
+  // and end up with an appropriately chained tree.
+
+  ResultExpr expr = std::move(else_result);
+  for (const Clause& clause : clause_list_) {
+    expr = std::make_shared<IfThenResultExprImpl>(clause.first, clause.second,
+                                                  std::move(expr));
+  }
+  return expr;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+namespace std {
+template class shared_ptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
+template class shared_ptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
+}  // namespace std
diff --git a/libchrome/sandbox/linux/bpf_dsl/bpf_dsl.h b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl.h
new file mode 100644
index 0000000..7f81344
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl.h
@@ -0,0 +1,335 @@
+// 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 SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/cons.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/sandbox_export.h"
+
+// The sandbox::bpf_dsl namespace provides a domain-specific language
+// to make writing BPF policies more expressive.  In general, the
+// object types all have value semantics (i.e., they can be copied
+// around, returned from or passed to function calls, etc. without any
+// surprising side effects), though not all support assignment.
+//
+// An idiomatic and demonstrative (albeit silly) example of this API
+// would be:
+//
+//      #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+//
+//      using namespace sandbox::bpf_dsl;
+//
+//      class SillyPolicy : public Policy {
+//       public:
+//        SillyPolicy() {}
+//        ~SillyPolicy() override {}
+//        ResultExpr EvaluateSyscall(int sysno) const override {
+//          if (sysno == __NR_fcntl) {
+//            Arg<int> fd(0), cmd(1);
+//            Arg<unsigned long> flags(2);
+//            const uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK;
+//            return If(AllOf(fd == 0,
+//                            cmd == F_SETFL,
+//                            (flags & ~kGoodFlags) == 0),
+//                      Allow())
+//                .ElseIf(AnyOf(cmd == F_DUPFD, cmd == F_DUPFD_CLOEXEC),
+//                        Error(EMFILE))
+//                .Else(Trap(SetFlagHandler, NULL));
+//          } else {
+//            return Allow();
+//          }
+//        }
+//
+//       private:
+//        DISALLOW_COPY_AND_ASSIGN(SillyPolicy);
+//      };
+//
+// More generally, the DSL currently supports the following grammar:
+//
+//   result = Allow() | Error(errno) | Kill() | Trace(aux)
+//          | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux)
+//          | If(bool, result)[.ElseIf(bool, result)].Else(result)
+//          | Switch(arg)[.Case(val, result)].Default(result)
+//   bool   = BoolConst(boolean) | Not(bool) | AllOf(bool...) | AnyOf(bool...)
+//          | arg == val | arg != val
+//   arg    = Arg<T>(num) | arg & mask
+//
+// The semantics of each function and operator are intended to be
+// intuitive, but are described in more detail below.
+//
+// (Credit to Sean Parent's "Inheritance is the Base Class of Evil"
+// talk at Going Native 2013 for promoting value semantics via shared
+// pointers to immutable state.)
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// ResultExpr is an opaque reference to an immutable result expression tree.
+using ResultExpr = std::shared_ptr<const internal::ResultExprImpl>;
+
+// BoolExpr is an opaque reference to an immutable boolean expression tree.
+using BoolExpr = std::shared_ptr<const internal::BoolExprImpl>;
+
+// Allow specifies a result that the system call should be allowed to
+// execute normally.
+SANDBOX_EXPORT ResultExpr Allow();
+
+// Error specifies a result that the system call should fail with
+// error number |err|.  As a special case, Error(0) will result in the
+// system call appearing to have succeeded, but without having any
+// side effects.
+SANDBOX_EXPORT ResultExpr Error(int err);
+
+// Kill specifies a result to kill the process (task) immediately.
+SANDBOX_EXPORT ResultExpr Kill();
+
+// Trace specifies a result to notify a tracing process via the
+// PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call.
+// The value of |aux| will be available to the tracer via PTRACE_GETEVENTMSG.
+SANDBOX_EXPORT ResultExpr Trace(uint16_t aux);
+
+// Trap specifies a result that the system call should be handled by
+// trapping back into userspace and invoking |trap_func|, passing
+// |aux| as the second parameter.
+SANDBOX_EXPORT ResultExpr
+    Trap(TrapRegistry::TrapFnc trap_func, const void* aux);
+
+// UnsafeTrap is like Trap, except the policy is marked as "unsafe"
+// and allowed to use SandboxSyscall to invoke any system call.
+//
+// NOTE: This feature, by definition, disables all security features of
+//   the sandbox. It should never be used in production, but it can be
+//   very useful to diagnose code that is incompatible with the sandbox.
+//   If even a single system call returns "UnsafeTrap", the security of
+//   entire sandbox should be considered compromised.
+SANDBOX_EXPORT ResultExpr
+    UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux);
+
+// BoolConst converts a bool value into a BoolExpr.
+SANDBOX_EXPORT BoolExpr BoolConst(bool value);
+
+// Not returns a BoolExpr representing the logical negation of |cond|.
+SANDBOX_EXPORT BoolExpr Not(BoolExpr cond);
+
+// AllOf returns a BoolExpr representing the logical conjunction ("and")
+// of zero or more BoolExprs.
+SANDBOX_EXPORT BoolExpr AllOf();
+SANDBOX_EXPORT BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs);
+template <typename... Rest>
+SANDBOX_EXPORT BoolExpr AllOf(BoolExpr first, Rest&&... rest);
+
+// AnyOf returns a BoolExpr representing the logical disjunction ("or")
+// of zero or more BoolExprs.
+SANDBOX_EXPORT BoolExpr AnyOf();
+SANDBOX_EXPORT BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs);
+template <typename... Rest>
+SANDBOX_EXPORT BoolExpr AnyOf(BoolExpr first, Rest&&... rest);
+
+template <typename T>
+class SANDBOX_EXPORT Arg {
+ public:
+  // Initializes the Arg to represent the |num|th system call
+  // argument (indexed from 0), which is of type |T|.
+  explicit Arg(int num);
+
+  Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {}
+
+  // Returns an Arg representing the current argument, but after
+  // bitwise-and'ing it with |rhs|.
+  friend Arg operator&(const Arg& lhs, uint64_t rhs) {
+    return Arg(lhs.num_, lhs.mask_ & rhs);
+  }
+
+  // Returns a boolean expression comparing whether the system call argument
+  // (after applying any bitmasks, if appropriate) equals |rhs|.
+  friend BoolExpr operator==(const Arg& lhs, T rhs) { return lhs.EqualTo(rhs); }
+
+  // Returns a boolean expression comparing whether the system call argument
+  // (after applying any bitmasks, if appropriate) does not equal |rhs|.
+  friend BoolExpr operator!=(const Arg& lhs, T rhs) { return Not(lhs == rhs); }
+
+ private:
+  Arg(int num, uint64_t mask) : num_(num), mask_(mask) {}
+
+  BoolExpr EqualTo(T val) const;
+
+  int num_;
+  uint64_t mask_;
+
+  DISALLOW_ASSIGN(Arg);
+};
+
+// If begins a conditional result expression predicated on the
+// specified boolean expression.
+SANDBOX_EXPORT Elser If(BoolExpr cond, ResultExpr then_result);
+
+class SANDBOX_EXPORT Elser {
+ public:
+  Elser(const Elser& elser);
+  ~Elser();
+
+  // ElseIf extends the conditional result expression with another
+  // "if then" clause, predicated on the specified boolean expression.
+  Elser ElseIf(BoolExpr cond, ResultExpr then_result) const;
+
+  // Else terminates a conditional result expression using |else_result| as
+  // the default fallback result expression.
+  ResultExpr Else(ResultExpr else_result) const;
+
+ private:
+  using Clause = std::pair<BoolExpr, ResultExpr>;
+
+  explicit Elser(cons::List<Clause> clause_list);
+
+  cons::List<Clause> clause_list_;
+
+  friend Elser If(BoolExpr, ResultExpr);
+  template <typename T>
+  friend Caser<T> Switch(const Arg<T>&);
+  DISALLOW_ASSIGN(Elser);
+};
+
+// Switch begins a switch expression dispatched according to the
+// specified argument value.
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg);
+
+template <typename T>
+class SANDBOX_EXPORT Caser {
+ public:
+  Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {}
+  ~Caser() {}
+
+  // Case adds a single-value "case" clause to the switch.
+  Caser<T> Case(T value, ResultExpr result) const;
+
+  // Cases adds a multiple-value "case" clause to the switch.
+  // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way
+  // of using this function.
+  template <typename... Values>
+  Caser<T> CasesImpl(ResultExpr result, const Values&... values) const;
+
+  // Terminate the switch with a "default" clause.
+  ResultExpr Default(ResultExpr result) const;
+
+ private:
+  Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {}
+
+  Arg<T> arg_;
+  Elser elser_;
+
+  template <typename U>
+  friend Caser<U> Switch(const Arg<U>&);
+  DISALLOW_ASSIGN(Caser);
+};
+
+// Recommended usage is to put
+//    #define CASES SANDBOX_BPF_DSL_CASES
+// near the top of the .cc file (e.g., nearby any "using" statements), then
+// use like:
+//    Switch(arg).CASES((3, 5, 7), result)...;
+#define SANDBOX_BPF_DSL_CASES(values, result) \
+  CasesImpl(result, SANDBOX_BPF_DSL_CASES_HELPER values)
+
+// Helper macro to strip parentheses.
+#define SANDBOX_BPF_DSL_CASES_HELPER(...) __VA_ARGS__
+
+// =====================================================================
+// Official API ends here.
+// =====================================================================
+
+namespace internal {
+
+// Make argument-dependent lookup work.  This is necessary because although
+// BoolExpr is defined in bpf_dsl, since it's merely a typedef for
+// scoped_refptr<const internal::BoolExplImpl>, argument-dependent lookup only
+// searches the "internal" nested namespace.
+using bpf_dsl::Not;
+using bpf_dsl::AllOf;
+using bpf_dsl::AnyOf;
+
+// Returns a boolean expression that represents whether system call
+// argument |num| of size |size| is equal to |val|, when masked
+// according to |mask|.  Users should use the Arg template class below
+// instead of using this API directly.
+SANDBOX_EXPORT BoolExpr
+    ArgEq(int num, size_t size, uint64_t mask, uint64_t val);
+
+// Returns the default mask for a system call argument of the specified size.
+SANDBOX_EXPORT uint64_t DefaultMask(size_t size);
+
+}  // namespace internal
+
+template <typename T>
+Arg<T>::Arg(int num)
+    : num_(num), mask_(internal::DefaultMask(sizeof(T))) {
+}
+
+// Definition requires ArgEq to have been declared.  Moved out-of-line
+// to minimize how much internal clutter users have to ignore while
+// reading the header documentation.
+//
+// Additionally, we use this helper member function to avoid linker errors
+// caused by defining operator== out-of-line.  For a more detailed explanation,
+// see http://www.parashift.com/c++-faq-lite/template-friends.html.
+template <typename T>
+BoolExpr Arg<T>::EqualTo(T val) const {
+  if (sizeof(T) == 4) {
+    // Prevent sign-extension of negative int32_t values.
+    return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint32_t>(val));
+  }
+  return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val));
+}
+
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) {
+  return Caser<T>(arg, Elser(nullptr));
+}
+
+template <typename T>
+Caser<T> Caser<T>::Case(T value, ResultExpr result) const {
+  return SANDBOX_BPF_DSL_CASES((value), std::move(result));
+}
+
+template <typename T>
+template <typename... Values>
+Caser<T> Caser<T>::CasesImpl(ResultExpr result, const Values&... values) const {
+  // Theoretically we could evaluate arg_ just once and emit a more efficient
+  // dispatch table, but for now we simply translate into an equivalent
+  // If/ElseIf/Else chain.
+
+  return Caser<T>(arg_,
+                  elser_.ElseIf(AnyOf((arg_ == values)...), std::move(result)));
+}
+
+template <typename T>
+ResultExpr Caser<T>::Default(ResultExpr result) const {
+  return elser_.Else(std::move(result));
+}
+
+template <typename... Rest>
+BoolExpr AllOf(BoolExpr first, Rest&&... rest) {
+  return AllOf(std::move(first), AllOf(std::forward<Rest>(rest)...));
+}
+
+template <typename... Rest>
+BoolExpr AnyOf(BoolExpr first, Rest&&... rest) {
+  return AnyOf(std::move(first), AnyOf(std::forward<Rest>(rest)...));
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_forward.h b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
new file mode 100644
index 0000000..10477c9
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
+
+#include <memory>
+
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// The bpf_dsl_forward.h header provides forward declarations for the
+// types defined in bpf_dsl.h. It's intended for use in user headers
+// that need to reference bpf_dsl types, but don't require definitions.
+
+namespace internal {
+class ResultExprImpl;
+class BoolExprImpl;
+}
+
+using ResultExpr = std::shared_ptr<const internal::ResultExprImpl>;
+using BoolExpr = std::shared_ptr<const internal::BoolExprImpl>;
+
+template <typename T>
+class Arg;
+
+class Elser;
+
+template <typename T>
+class Caser;
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+namespace std {
+extern template class SANDBOX_EXPORT
+    shared_ptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
+extern template class SANDBOX_EXPORT
+    shared_ptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
+}  // namespace std
+
+#endif  // SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_impl.h b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
new file mode 100644
index 0000000..35ff64f
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class ErrorCode;
+class PolicyCompiler;
+
+namespace internal {
+
+// Internal interface implemented by BoolExpr implementations.
+class BoolExprImpl {
+ public:
+  // Compile uses |pc| to emit a CodeGen::Node that conditionally continues
+  // to either |then_node| or |false_node|, depending on whether the represented
+  // boolean expression is true or false.
+  virtual CodeGen::Node Compile(PolicyCompiler* pc,
+                                CodeGen::Node then_node,
+                                CodeGen::Node else_node) const = 0;
+
+ protected:
+  BoolExprImpl() {}
+  virtual ~BoolExprImpl() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BoolExprImpl);
+};
+
+// Internal interface implemented by ResultExpr implementations.
+class ResultExprImpl {
+ public:
+  // Compile uses |pc| to emit a CodeGen::Node that executes the
+  // represented result expression.
+  virtual CodeGen::Node Compile(PolicyCompiler* pc) const = 0;
+
+  // HasUnsafeTraps returns whether the result expression is or recursively
+  // contains an unsafe trap expression.
+  virtual bool HasUnsafeTraps() const;
+
+  // IsAllow returns whether the result expression is an "allow" result.
+  virtual bool IsAllow() const;
+
+  // IsAllow returns whether the result expression is a "deny" result.
+  virtual bool IsDeny() const;
+
+ protected:
+  ResultExprImpl() {}
+  virtual ~ResultExprImpl() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResultExprImpl);
+};
+
+}  // namespace internal
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
new file mode 100644
index 0000000..801deee
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/bpf_dsl_unittest.cc
@@ -0,0 +1,478 @@
+// 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 "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include <map>
+#include <utility>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/dump_bpf.h"
+#include "sandbox/linux/bpf_dsl/golden/golden_files.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/test_trap_registry.h"
+#include "sandbox/linux/bpf_dsl/verifier.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define CASES SANDBOX_BPF_DSL_CASES
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace {
+
+// Helper function to construct fake arch_seccomp_data objects.
+struct arch_seccomp_data FakeSyscall(int nr,
+                                     uintptr_t p0 = 0,
+                                     uintptr_t p1 = 0,
+                                     uintptr_t p2 = 0,
+                                     uintptr_t p3 = 0,
+                                     uintptr_t p4 = 0,
+                                     uintptr_t p5 = 0) {
+  // Made up program counter for syscall address.
+  const uint64_t kFakePC = 0x543210;
+
+  struct arch_seccomp_data data = {
+      nr,
+      SECCOMP_ARCH,
+      kFakePC,
+      {
+       p0, p1, p2, p3, p4, p5,
+      },
+  };
+
+  return data;
+}
+
+class PolicyEmulator {
+ public:
+  PolicyEmulator(const golden::Golden& golden, const Policy& policy)
+      : program_() {
+    TestTrapRegistry traps;
+    program_ = PolicyCompiler(&policy, &traps).Compile();
+
+    // TODO(mdempsky): Generalize to more arches.
+    const char* expected = nullptr;
+#if defined(ARCH_CPU_X86)
+    expected = golden.i386_dump;
+#elif defined(ARCH_CPU_X86_64)
+    expected = golden.x86_64_dump;
+#endif
+
+    if (expected != nullptr) {
+      const std::string actual = DumpBPF::StringPrintProgram(program_);
+      EXPECT_EQ(expected, actual);
+    } else {
+      LOG(WARNING) << "Missing golden file data entry";
+    }
+  }
+
+  ~PolicyEmulator() {}
+
+  void ExpectAllow(const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_ALLOW, Emulate(data));
+  }
+
+  void ExpectErrno(uint16_t err, const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_ERRNO | err, Emulate(data));
+  }
+
+  void ExpectKill(const struct arch_seccomp_data& data) const {
+    EXPECT_EQ(SECCOMP_RET_KILL, Emulate(data));
+  }
+
+ private:
+  uint32_t Emulate(const struct arch_seccomp_data& data) const {
+    const char* err = nullptr;
+    uint32_t res = Verifier::EvaluateBPF(program_, data, &err);
+    if (err) {
+      ADD_FAILURE() << err;
+      return 0;
+    }
+    return res;
+  }
+
+  CodeGen::Program program_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyEmulator);
+};
+
+class BasicPolicy : public Policy {
+ public:
+  BasicPolicy() {}
+  ~BasicPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_getpgid) {
+      const Arg<pid_t> pid(0);
+      return If(pid == 0, Error(EPERM)).Else(Error(EINVAL));
+    }
+    if (sysno == __NR_setuid) {
+      const Arg<uid_t> uid(0);
+      return If(uid != 42, Kill()).Else(Allow());
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicPolicy);
+};
+
+TEST(BPFDSL, Basic) {
+  PolicyEmulator emulator(golden::kBasicPolicy, BasicPolicy());
+
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_getpgid, 0));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_getpgid, 1));
+
+  emulator.ExpectAllow(FakeSyscall(__NR_setuid, 42));
+  emulator.ExpectKill(FakeSyscall(__NR_setuid, 43));
+}
+
+/* On IA-32, socketpair() is implemented via socketcall(). :-( */
+#if !defined(ARCH_CPU_X86)
+class BooleanLogicPolicy : public Policy {
+ public:
+  BooleanLogicPolicy() {}
+  ~BooleanLogicPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_socketpair) {
+      const Arg<int> domain(0), type(1), protocol(2);
+      return If(AllOf(domain == AF_UNIX,
+                      AnyOf(type == SOCK_STREAM, type == SOCK_DGRAM),
+                      protocol == 0),
+                Error(EPERM))
+          .Else(Error(EINVAL));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy);
+};
+
+TEST(BPFDSL, BooleanLogic) {
+  PolicyEmulator emulator(golden::kBooleanLogicPolicy, BooleanLogicPolicy());
+
+  const intptr_t kFakeSV = 0x12345;
+
+  // Acceptable combinations that should return EPERM.
+  emulator.ExpectErrno(
+      EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_STREAM, 0, kFakeSV));
+  emulator.ExpectErrno(
+      EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_DGRAM, 0, kFakeSV));
+
+  // Combinations that are invalid for only one reason; should return EINVAL.
+  emulator.ExpectErrno(
+      EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_STREAM, 0, kFakeSV));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX,
+                                           SOCK_SEQPACKET, 0, kFakeSV));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX,
+                                           SOCK_STREAM, IPPROTO_TCP, kFakeSV));
+
+  // Completely unacceptable combination; should also return EINVAL.
+  emulator.ExpectErrno(
+      EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_SEQPACKET, IPPROTO_UDP,
+                          kFakeSV));
+}
+#endif  // !ARCH_CPU_X86
+
+class MoreBooleanLogicPolicy : public Policy {
+ public:
+  MoreBooleanLogicPolicy() {}
+  ~MoreBooleanLogicPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_setresuid) {
+      const Arg<uid_t> ruid(0), euid(1), suid(2);
+      return If(AnyOf(ruid == 0, euid == 0, suid == 0), Error(EPERM))
+          .ElseIf(AllOf(ruid == 1, euid == 1, suid == 1), Error(EAGAIN))
+          .Else(Error(EINVAL));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MoreBooleanLogicPolicy);
+};
+
+TEST(BPFDSL, MoreBooleanLogic) {
+  PolicyEmulator emulator(golden::kMoreBooleanLogicPolicy,
+                          MoreBooleanLogicPolicy());
+
+  // Expect EPERM if any set to 0.
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 0, 5, 5));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 0, 5));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 5, 0));
+
+  // Expect EAGAIN if all set to 1.
+  emulator.ExpectErrno(EAGAIN, FakeSyscall(__NR_setresuid, 1, 1, 1));
+
+  // Expect EINVAL for anything else.
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 5, 1, 1));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 5, 1));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 1, 5));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 3, 4, 5));
+}
+
+static const uintptr_t kDeadBeefAddr =
+    static_cast<uintptr_t>(0xdeadbeefdeadbeefULL);
+
+class ArgSizePolicy : public Policy {
+ public:
+  ArgSizePolicy() {}
+  ~ArgSizePolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_uname) {
+      const Arg<uintptr_t> addr(0);
+      return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow());
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy);
+};
+
+TEST(BPFDSL, ArgSizeTest) {
+  PolicyEmulator emulator(golden::kArgSizePolicy, ArgSizePolicy());
+
+  emulator.ExpectAllow(FakeSyscall(__NR_uname, 0));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_uname, kDeadBeefAddr));
+}
+
+class NegativeConstantsPolicy : public Policy {
+ public:
+  NegativeConstantsPolicy() {}
+  ~NegativeConstantsPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_fcntl) {
+      const Arg<int> fd(0);
+      return If(fd == -314, Error(EPERM)).Else(Allow());
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NegativeConstantsPolicy);
+};
+
+TEST(BPFDSL, NegativeConstantsTest) {
+  PolicyEmulator emulator(golden::kNegativeConstantsPolicy,
+                          NegativeConstantsPolicy());
+
+  emulator.ExpectAllow(FakeSyscall(__NR_fcntl, -5, F_DUPFD));
+  emulator.ExpectAllow(FakeSyscall(__NR_fcntl, 20, F_DUPFD));
+  emulator.ExpectErrno(EPERM, FakeSyscall(__NR_fcntl, -314, F_DUPFD));
+}
+
+#if 0
+// TODO(mdempsky): This is really an integration test.
+
+class TrappingPolicy : public Policy {
+ public:
+  TrappingPolicy() {}
+  ~TrappingPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_uname) {
+      return Trap(UnameTrap, &count_);
+    }
+    return Allow();
+  }
+
+ private:
+  static intptr_t count_;
+
+  static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) {
+    BPF_ASSERT_EQ(&count_, aux);
+    return ++count_;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(TrappingPolicy);
+};
+
+intptr_t TrappingPolicy::count_;
+
+BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) {
+  ASSERT_SYSCALL_RESULT(1, uname, NULL);
+  ASSERT_SYSCALL_RESULT(2, uname, NULL);
+  ASSERT_SYSCALL_RESULT(3, uname, NULL);
+}
+#endif
+
+class MaskingPolicy : public Policy {
+ public:
+  MaskingPolicy() {}
+  ~MaskingPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_setuid) {
+      const Arg<uid_t> uid(0);
+      return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES));
+    }
+    if (sysno == __NR_setgid) {
+      const Arg<gid_t> gid(0);
+      return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES));
+    }
+    if (sysno == __NR_setpgid) {
+      const Arg<pid_t> pid(0);
+      return If((pid & 0xa5) == 0xa0, Error(EINVAL)).Else(Error(EACCES));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MaskingPolicy);
+};
+
+TEST(BPFDSL, MaskTest) {
+  PolicyEmulator emulator(golden::kMaskingPolicy, MaskingPolicy());
+
+  for (uid_t uid = 0; uid < 0x100; ++uid) {
+    const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES;
+    emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setuid, uid));
+  }
+
+  for (gid_t gid = 0; gid < 0x100; ++gid) {
+    const int expect_errno = (gid & 0xf0) == 0xf0 ? EINVAL : EACCES;
+    emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setgid, gid));
+  }
+
+  for (pid_t pid = 0; pid < 0x100; ++pid) {
+    const int expect_errno = (pid & 0xa5) == 0xa0 ? EINVAL : EACCES;
+    emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setpgid, pid, 0));
+  }
+}
+
+class ElseIfPolicy : public Policy {
+ public:
+  ElseIfPolicy() {}
+  ~ElseIfPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_setuid) {
+      const Arg<uid_t> uid(0);
+      return If((uid & 0xfff) == 0, Error(0))
+          .ElseIf((uid & 0xff0) == 0, Error(EINVAL))
+          .ElseIf((uid & 0xf00) == 0, Error(EEXIST))
+          .Else(Error(EACCES));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy);
+};
+
+TEST(BPFDSL, ElseIfTest) {
+  PolicyEmulator emulator(golden::kElseIfPolicy, ElseIfPolicy());
+
+  emulator.ExpectErrno(0, FakeSyscall(__NR_setuid, 0));
+
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0001));
+  emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0002));
+
+  emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0011));
+  emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0022));
+
+  emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0111));
+  emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0222));
+}
+
+class SwitchPolicy : public Policy {
+ public:
+  SwitchPolicy() {}
+  ~SwitchPolicy() override {}
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    if (sysno == __NR_fcntl) {
+      const Arg<int> cmd(1);
+      const Arg<unsigned long> long_arg(2);
+      return Switch(cmd)
+          .CASES((F_GETFL, F_GETFD), Error(ENOENT))
+          .Case(F_SETFD, If(long_arg == O_CLOEXEC, Allow()).Else(Error(EINVAL)))
+          .Case(F_SETFL, Error(EPERM))
+          .Default(Error(EACCES));
+    }
+    return Allow();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SwitchPolicy);
+};
+
+TEST(BPFDSL, SwitchTest) {
+  PolicyEmulator emulator(golden::kSwitchPolicy, SwitchPolicy());
+
+  const int kFakeSockFD = 42;
+
+  emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFD));
+  emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFL));
+
+  emulator.ExpectAllow(
+      FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, O_CLOEXEC));
+  emulator.ExpectErrno(EINVAL,
+                       FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, 0));
+
+  emulator.ExpectErrno(EPERM,
+                       FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFL, O_RDONLY));
+
+  emulator.ExpectErrno(EACCES,
+                       FakeSyscall(__NR_fcntl, kFakeSockFD, F_DUPFD, 0));
+}
+
+static intptr_t DummyTrap(const struct arch_seccomp_data& data, void* aux) {
+  return 0;
+}
+
+TEST(BPFDSL, IsAllowDeny) {
+  ResultExpr allow = Allow();
+  EXPECT_TRUE(allow->IsAllow());
+  EXPECT_FALSE(allow->IsDeny());
+
+  ResultExpr error = Error(ENOENT);
+  EXPECT_FALSE(error->IsAllow());
+  EXPECT_TRUE(error->IsDeny());
+
+  ResultExpr trace = Trace(42);
+  EXPECT_FALSE(trace->IsAllow());
+  EXPECT_FALSE(trace->IsDeny());
+
+  ResultExpr trap = Trap(DummyTrap, nullptr);
+  EXPECT_FALSE(trap->IsAllow());
+  EXPECT_TRUE(trap->IsDeny());
+
+  const Arg<int> arg(0);
+  ResultExpr maybe = If(arg == 0, Allow()).Else(Error(EPERM));
+  EXPECT_FALSE(maybe->IsAllow());
+  EXPECT_FALSE(maybe->IsDeny());
+}
+
+TEST(BPFDSL, HasUnsafeTraps) {
+  ResultExpr allow = Allow();
+  EXPECT_FALSE(allow->HasUnsafeTraps());
+
+  ResultExpr safe = Trap(DummyTrap, nullptr);
+  EXPECT_FALSE(safe->HasUnsafeTraps());
+
+  ResultExpr unsafe = UnsafeTrap(DummyTrap, nullptr);
+  EXPECT_TRUE(unsafe->HasUnsafeTraps());
+
+  const Arg<int> arg(0);
+  ResultExpr maybe = If(arg == 0, allow).Else(unsafe);
+  EXPECT_TRUE(maybe->HasUnsafeTraps());
+}
+
+}  // namespace
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/codegen.cc b/libchrome/sandbox/linux/bpf_dsl/codegen.cc
new file mode 100644
index 0000000..d88bd53
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/codegen.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 "sandbox/linux/bpf_dsl/codegen.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <utility>
+
+#include "base/logging.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+
+// This CodeGen implementation strives for simplicity while still
+// generating acceptable BPF programs under typical usage patterns
+// (e.g., by PolicyCompiler).
+//
+// The key to its simplicity is that BPF programs only support forward
+// jumps/branches, which allows constraining the DAG construction API
+// to make instruction nodes immutable. Immutable nodes admits a
+// simple greedy approach of emitting new instructions as needed and
+// then reusing existing ones that have already been emitted. This
+// cleanly avoids any need to compute basic blocks or apply
+// topological sorting because the API effectively sorts instructions
+// for us (e.g., before MakeInstruction() can be called to emit a
+// branch instruction, it must have already been called for each
+// branch path).
+//
+// This greedy algorithm is not without (theoretical) weakness though:
+//
+//   1. In the general case, we don't eliminate dead code.  If needed,
+//      we could trace back through the program in Compile() and elide
+//      any unneeded instructions, but in practice we only emit live
+//      instructions anyway.
+//
+//   2. By not dividing instructions into basic blocks and sorting, we
+//      lose an opportunity to move non-branch/non-return instructions
+//      adjacent to their successor instructions, which means we might
+//      need to emit additional jumps. But in practice, they'll
+//      already be nearby as long as callers don't go out of their way
+//      to interleave MakeInstruction() calls for unrelated code
+//      sequences.
+
+namespace sandbox {
+
+// kBranchRange is the maximum value that can be stored in
+// sock_filter's 8-bit jt and jf fields.
+const size_t kBranchRange = std::numeric_limits<uint8_t>::max();
+
+const CodeGen::Node CodeGen::kNullNode;
+
+CodeGen::CodeGen() : program_(), equivalent_(), memos_() {
+}
+
+CodeGen::~CodeGen() {
+}
+
+CodeGen::Program CodeGen::Compile(CodeGen::Node head) {
+  return Program(program_.rbegin() + Offset(head), program_.rend());
+}
+
+CodeGen::Node CodeGen::MakeInstruction(uint16_t code,
+                                       uint32_t k,
+                                       Node jt,
+                                       Node jf) {
+  // To avoid generating redundant code sequences, we memoize the
+  // results from AppendInstruction().
+  auto res = memos_.insert(std::make_pair(MemoKey(code, k, jt, jf), kNullNode));
+  CodeGen::Node* node = &res.first->second;
+  if (res.second) {  // Newly inserted memo entry.
+    *node = AppendInstruction(code, k, jt, jf);
+  }
+  return *node;
+}
+
+CodeGen::Node CodeGen::AppendInstruction(uint16_t code,
+                                         uint32_t k,
+                                         Node jt,
+                                         Node jf) {
+  if (BPF_CLASS(code) == BPF_JMP) {
+    CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed";
+
+    // Optimally adding jumps is rather tricky, so we use a quick
+    // approximation: by artificially reducing |jt|'s range, |jt| will
+    // stay within its true range even if we add a jump for |jf|.
+    jt = WithinRange(jt, kBranchRange - 1);
+    jf = WithinRange(jf, kBranchRange);
+    return Append(code, k, Offset(jt), Offset(jf));
+  }
+
+  CHECK_EQ(kNullNode, jf) << "Non-branch instructions shouldn't provide jf";
+  if (BPF_CLASS(code) == BPF_RET) {
+    CHECK_EQ(kNullNode, jt) << "Return instructions shouldn't provide jt";
+  } else {
+    // For non-branch/non-return instructions, execution always
+    // proceeds to the next instruction; so we need to arrange for
+    // that to be |jt|.
+    jt = WithinRange(jt, 0);
+    CHECK_EQ(0U, Offset(jt)) << "ICE: Failed to setup next instruction";
+  }
+  return Append(code, k, 0, 0);
+}
+
+CodeGen::Node CodeGen::WithinRange(Node target, size_t range) {
+  // Just use |target| if it's already within range.
+  if (Offset(target) <= range) {
+    return target;
+  }
+
+  // Alternatively, look for an equivalent instruction within range.
+  if (Offset(equivalent_.at(target)) <= range) {
+    return equivalent_.at(target);
+  }
+
+  // Otherwise, fall back to emitting a jump instruction.
+  Node jump = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0);
+  equivalent_.at(target) = jump;
+  return jump;
+}
+
+CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) {
+  if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) {
+    CHECK_LE(jt, kBranchRange);
+    CHECK_LE(jf, kBranchRange);
+  } else {
+    CHECK_EQ(0U, jt);
+    CHECK_EQ(0U, jf);
+  }
+
+  CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS));
+  CHECK_EQ(program_.size(), equivalent_.size());
+
+  Node res = program_.size();
+  program_.push_back(sock_filter{
+      code, static_cast<uint8_t>(jt), static_cast<uint8_t>(jf), k});
+  equivalent_.push_back(res);
+  return res;
+}
+
+size_t CodeGen::Offset(Node target) const {
+  CHECK_LT(target, program_.size()) << "Bogus offset target node";
+  return (program_.size() - 1) - target;
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/codegen.h b/libchrome/sandbox/linux/bpf_dsl/codegen.h
new file mode 100644
index 0000000..3fc3f35
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/codegen.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 SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
+#define SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <tuple>
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+struct sock_filter;
+
+namespace sandbox {
+
+// The code generator implements a basic assembler that can convert a
+// graph of BPF instructions into a well-formed array of BPF
+// instructions. Most notably, it ensures that jumps are always
+// forward and don't exceed the limit of 255 instructions imposed by
+// the instruction set.
+//
+// Callers would typically create a new CodeGen object and then use it
+// to build a DAG of instruction nodes. They'll eventually call
+// Compile() to convert this DAG to a Program.
+//
+//   CodeGen gen;
+//   CodeGen::Node allow, branch, dag;
+//
+//   allow =
+//     gen.MakeInstruction(BPF_RET+BPF_K,
+//                         ErrorCode(ErrorCode::ERR_ALLOWED).err()));
+//   branch =
+//     gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid,
+//                         Trap(GetPidHandler, NULL), allow);
+//   dag =
+//     gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
+//                         offsetof(struct arch_seccomp_data, nr), branch);
+//
+//   // Simplified code follows; in practice, it is important to avoid calling
+//   // any C++ destructors after starting the sandbox.
+//   CodeGen::Program program = gen.Compile(dag);
+//   const struct sock_fprog prog = {
+//     static_cast<unsigned short>(program.size()), &program[0] };
+//   prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
+//
+class SANDBOX_EXPORT CodeGen {
+ public:
+  // A vector of BPF instructions that need to be installed as a filter
+  // program in the kernel.
+  typedef std::vector<struct sock_filter> Program;
+
+  // Node represents a node within the instruction DAG being compiled.
+  using Node = Program::size_type;
+
+  // kNullNode represents the "null" node; i.e., the reserved node
+  // value guaranteed to not equal any actual nodes.
+  static const Node kNullNode = -1;
+
+  CodeGen();
+  ~CodeGen();
+
+  // MakeInstruction creates a node representing the specified
+  // instruction, or returns and existing equivalent node if one
+  // exists. For details on the possible parameters refer to
+  // https://www.kernel.org/doc/Documentation/networking/filter.txt.
+  // TODO(mdempsky): Reconsider using default arguments here.
+  Node MakeInstruction(uint16_t code,
+                       uint32_t k,
+                       Node jt = kNullNode,
+                       Node jf = kNullNode);
+
+  // Compile linearizes the instruction DAG rooted at |head| into a
+  // program that can be executed by a BPF virtual machine.
+  Program Compile(Node head);
+
+ private:
+  using MemoKey = std::tuple<uint16_t, uint32_t, Node, Node>;
+
+  // AppendInstruction adds a new instruction, ensuring that |jt| and
+  // |jf| are within range as necessary for |code|.
+  Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf);
+
+  // WithinRange returns a node equivalent to |next| that is at most
+  // |range| instructions away from the (logical) beginning of the
+  // program.
+  Node WithinRange(Node next, size_t range);
+
+  // Append appends a new instruction to the physical end (i.e.,
+  // logical beginning) of |program_|.
+  Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf);
+
+  // Offset returns how many instructions exist in |program_| after |target|.
+  size_t Offset(Node target) const;
+
+  // NOTE: program_ is the compiled program in *reverse*, so that
+  // indices remain stable as we add instructions.
+  Program program_;
+
+  // equivalent_ stores the most recent semantically-equivalent node for each
+  // instruction in program_. A node is defined as semantically-equivalent to N
+  // if it has the same instruction code and constant as N and its successor
+  // nodes (if any) are semantically-equivalent to N's successor nodes, or
+  // if it's an unconditional jump to a node semantically-equivalent to N.
+  std::vector<Node> equivalent_;
+
+  std::map<MemoKey, Node> memos_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeGen);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
diff --git a/libchrome/sandbox/linux/bpf_dsl/codegen_unittest.cc b/libchrome/sandbox/linux/bpf_dsl/codegen_unittest.cc
new file mode 100644
index 0000000..56a0dd2
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/codegen_unittest.cc
@@ -0,0 +1,404 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/md5.h"
+#include "base/strings/string_piece.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace {
+
+// Hash provides an abstraction for building "hash trees" from BPF
+// control flow graphs, and efficiently identifying equivalent graphs.
+//
+// For simplicity, we use MD5, because base happens to provide a
+// convenient API for its use. However, any collision-resistant hash
+// should suffice.
+class Hash {
+ public:
+  static const Hash kZero;
+
+  Hash() : digest_() {}
+
+  Hash(uint16_t code,
+       uint32_t k,
+       const Hash& jt = kZero,
+       const Hash& jf = kZero)
+      : digest_() {
+    base::MD5Context ctx;
+    base::MD5Init(&ctx);
+    HashValue(&ctx, code);
+    HashValue(&ctx, k);
+    HashValue(&ctx, jt);
+    HashValue(&ctx, jf);
+    base::MD5Final(&digest_, &ctx);
+  }
+
+  Hash(const Hash& hash) = default;
+  Hash& operator=(const Hash& rhs) = default;
+
+  friend bool operator==(const Hash& lhs, const Hash& rhs) {
+    return lhs.Base16() == rhs.Base16();
+  }
+  friend bool operator!=(const Hash& lhs, const Hash& rhs) {
+    return !(lhs == rhs);
+  }
+
+ private:
+  template <typename T>
+  void HashValue(base::MD5Context* ctx, const T& value) {
+    base::MD5Update(ctx,
+                    base::StringPiece(reinterpret_cast<const char*>(&value),
+                                      sizeof(value)));
+  }
+
+  std::string Base16() const {
+    return base::MD5DigestToBase16(digest_);
+  }
+
+  base::MD5Digest digest_;
+};
+
+const Hash Hash::kZero;
+
+// Sanity check that equality and inequality work on Hash as required.
+TEST(CodeGen, HashSanity) {
+  std::vector<Hash> hashes;
+
+  // Push a bunch of logically distinct hashes.
+  hashes.push_back(Hash::kZero);
+  for (int i = 0; i < 4; ++i) {
+    hashes.push_back(Hash(i & 1, i & 2));
+  }
+  for (int i = 0; i < 16; ++i) {
+    hashes.push_back(Hash(i & 1, i & 2, Hash(i & 4, i & 8)));
+  }
+  for (int i = 0; i < 64; ++i) {
+    hashes.push_back(
+        Hash(i & 1, i & 2, Hash(i & 4, i & 8), Hash(i & 16, i & 32)));
+  }
+
+  for (const Hash& a : hashes) {
+    for (const Hash& b : hashes) {
+      // Hashes should equal themselves, but not equal all others.
+      if (&a == &b) {
+        EXPECT_EQ(a, b);
+      } else {
+        EXPECT_NE(a, b);
+      }
+    }
+  }
+}
+
+// ProgramTest provides a fixture for writing compiling sample
+// programs with CodeGen and verifying the linearized output matches
+// the input DAG.
+class ProgramTest : public ::testing::Test {
+ protected:
+  ProgramTest() : gen_(), node_hashes_() {}
+
+  // MakeInstruction calls CodeGen::MakeInstruction() and associated
+  // the returned address with a hash of the instruction.
+  CodeGen::Node MakeInstruction(uint16_t code,
+                                uint32_t k,
+                                CodeGen::Node jt = CodeGen::kNullNode,
+                                CodeGen::Node jf = CodeGen::kNullNode) {
+    CodeGen::Node res = gen_.MakeInstruction(code, k, jt, jf);
+    EXPECT_NE(CodeGen::kNullNode, res);
+
+    Hash digest(code, k, Lookup(jt), Lookup(jf));
+    auto it = node_hashes_.insert(std::make_pair(res, digest));
+    EXPECT_EQ(digest, it.first->second);
+
+    return res;
+  }
+
+  // RunTest compiles the program and verifies that the output matches
+  // what is expected.  It should be called at the end of each program
+  // test case.
+  void RunTest(CodeGen::Node head) {
+    // Compile the program
+    CodeGen::Program program = gen_.Compile(head);
+
+    // Walk the program backwards, and compute the hash for each instruction.
+    std::vector<Hash> prog_hashes(program.size());
+    for (size_t i = program.size(); i > 0; --i) {
+      const sock_filter& insn = program.at(i - 1);
+      Hash& hash = prog_hashes.at(i - 1);
+
+      if (BPF_CLASS(insn.code) == BPF_JMP) {
+        if (BPF_OP(insn.code) == BPF_JA) {
+          // The compiler adds JA instructions as needed, so skip them.
+          hash = prog_hashes.at(i + insn.k);
+        } else {
+          hash = Hash(insn.code, insn.k, prog_hashes.at(i + insn.jt),
+                      prog_hashes.at(i + insn.jf));
+        }
+      } else if (BPF_CLASS(insn.code) == BPF_RET) {
+        hash = Hash(insn.code, insn.k);
+      } else {
+        hash = Hash(insn.code, insn.k, prog_hashes.at(i));
+      }
+    }
+
+    EXPECT_EQ(Lookup(head), prog_hashes.at(0));
+  }
+
+ private:
+  const Hash& Lookup(CodeGen::Node next) const {
+    if (next == CodeGen::kNullNode) {
+      return Hash::kZero;
+    }
+    auto it = node_hashes_.find(next);
+    if (it == node_hashes_.end()) {
+      ADD_FAILURE() << "No hash found for node " << next;
+      return Hash::kZero;
+    }
+    return it->second;
+  }
+
+  CodeGen gen_;
+  std::map<CodeGen::Node, Hash> node_hashes_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProgramTest);
+};
+
+TEST_F(ProgramTest, OneInstruction) {
+  // Create the most basic valid BPF program:
+  //    RET 0
+  CodeGen::Node head = MakeInstruction(BPF_RET + BPF_K, 0);
+  RunTest(head);
+}
+
+TEST_F(ProgramTest, SimpleBranch) {
+  // Create a program with a single branch:
+  //    JUMP if eq 42 then $0 else $1
+  // 0: RET 1
+  // 1: RET 0
+  CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42,
+                                       MakeInstruction(BPF_RET + BPF_K, 1),
+                                       MakeInstruction(BPF_RET + BPF_K, 0));
+  RunTest(head);
+}
+
+TEST_F(ProgramTest, AtypicalBranch) {
+  // Create a program with a single branch:
+  //    JUMP if eq 42 then $0 else $0
+  // 0: RET 0
+
+  CodeGen::Node ret = MakeInstruction(BPF_RET + BPF_K, 0);
+  CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret);
+
+  // N.B.: As the instructions in both sides of the branch are already
+  //       the same object, we do not actually have any "mergeable" branches.
+  //       This needs to be reflected in our choice of "flags".
+  RunTest(head);
+}
+
+TEST_F(ProgramTest, Complex) {
+  // Creates a basic BPF program that we'll use to test some of the code:
+  //    JUMP if eq 42 the $0 else $1     (insn6)
+  // 0: LD 23                            (insn5)
+  // 1: JUMP if eq 42 then $2 else $4    (insn4)
+  // 2: JUMP to $3                       (insn2)
+  // 3: LD 42                            (insn1)
+  //    RET 42                           (insn0)
+  // 4: LD 42                            (insn3)
+  //    RET 42                           (insn3+)
+  CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42);
+  CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0);
+  CodeGen::Node insn2 = insn1;  // Implicit JUMP
+
+  // We explicitly duplicate instructions to test that they're merged.
+  CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42,
+                                        MakeInstruction(BPF_RET + BPF_K, 42));
+  EXPECT_EQ(insn2, insn3);
+
+  CodeGen::Node insn4 =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3);
+  CodeGen::Node insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4);
+
+  // Force a basic block that ends in neither a jump instruction nor a return
+  // instruction. It only contains "insn5". This exercises one of the less
+  // common code paths in the topo-sort algorithm.
+  // This also gives us a diamond-shaped pattern in our graph, which stresses
+  // another aspect of the topo-sort algorithm (namely, the ability to
+  // correctly count the incoming branches for subtrees that are not disjunct).
+  CodeGen::Node insn6 =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn5, insn4);
+
+  RunTest(insn6);
+}
+
+TEST_F(ProgramTest, ConfusingTails) {
+  // This simple program demonstrates https://crbug.com/351103/
+  // The two "LOAD 0" instructions are blocks of their own. MergeTails() could
+  // be tempted to merge them since they are the same. However, they are
+  // not mergeable because they fall-through to non semantically equivalent
+  // blocks.
+  // Without the fix for this bug, this program should trigger the check in
+  // CompileAndCompare: the serialized graphs from the program and its compiled
+  // version will differ.
+  //
+  //  0) LOAD 1  // ???
+  //  1) if A == 0x1; then JMP 2 else JMP 3
+  //  2) LOAD 0  // System call number
+  //  3) if A == 0x2; then JMP 4 else JMP 5
+  //  4) LOAD 0  // System call number
+  //  5) if A == 0x1; then JMP 6 else JMP 7
+  //  6) RET 0
+  //  7) RET 1
+
+  CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
+  CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
+  CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
+  CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
+  CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+  CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
+  CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+  CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+
+  RunTest(i0);
+}
+
+TEST_F(ProgramTest, ConfusingTailsBasic) {
+  // Without the fix for https://crbug.com/351103/, (see
+  // SampleProgramConfusingTails()), this would generate a cyclic graph and
+  // crash as the two "LOAD 0" instructions would get merged.
+  //
+  // 0) LOAD 1  // ???
+  // 1) if A == 0x1; then JMP 2 else JMP 3
+  // 2) LOAD 0  // System call number
+  // 3) if A == 0x2; then JMP 4 else JMP 5
+  // 4) LOAD 0  // System call number
+  // 5) RET 1
+
+  CodeGen::Node i5 = MakeInstruction(BPF_RET + BPF_K, 1);
+  CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
+  CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+  CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
+  CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+  CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+
+  RunTest(i0);
+}
+
+TEST_F(ProgramTest, ConfusingTailsMergeable) {
+  // This is similar to SampleProgramConfusingTails(), except that
+  // instructions 2 and 4 are now RET instructions.
+  // In PointerCompare(), this exercises the path where two blocks are of the
+  // same length and identical and the last instruction is a JMP or RET, so the
+  // following blocks don't need to be looked at and the blocks are mergeable.
+  //
+  // 0) LOAD 1  // ???
+  // 1) if A == 0x1; then JMP 2 else JMP 3
+  // 2) RET 42
+  // 3) if A == 0x2; then JMP 4 else JMP 5
+  // 4) RET 42
+  // 5) if A == 0x1; then JMP 6 else JMP 7
+  // 6) RET 0
+  // 7) RET 1
+
+  CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
+  CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
+  CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
+  CodeGen::Node i4 = MakeInstruction(BPF_RET + BPF_K, 42);
+  CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+  CodeGen::Node i2 = MakeInstruction(BPF_RET + BPF_K, 42);
+  CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+  CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+
+  RunTest(i0);
+}
+
+TEST_F(ProgramTest, InstructionFolding) {
+  // Check that simple instructions are folded as expected.
+  CodeGen::Node a = MakeInstruction(BPF_RET + BPF_K, 0);
+  EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0));
+  CodeGen::Node b = MakeInstruction(BPF_RET + BPF_K, 1);
+  EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0));
+  EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1));
+  EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1));
+
+  // Check that complex sequences are folded too.
+  CodeGen::Node c =
+      MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0,
+                      MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b));
+  EXPECT_EQ(c, MakeInstruction(
+                   BPF_LD + BPF_W + BPF_ABS, 0,
+                   MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b)));
+
+  RunTest(c);
+}
+
+TEST_F(ProgramTest, FarBranches) {
+  // BPF instructions use 8-bit fields for branch offsets, which means
+  // branch targets must be within 255 instructions of the branch
+  // instruction. CodeGen abstracts away this detail by inserting jump
+  // instructions as needed, which we test here by generating programs
+  // that should trigger any interesting boundary conditions.
+
+  // Populate with 260 initial instruction nodes.
+  std::vector<CodeGen::Node> nodes;
+  nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0));
+  for (size_t i = 1; i < 260; ++i) {
+    nodes.push_back(
+        MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back()));
+  }
+
+  // Exhaustively test branch offsets near BPF's limits.
+  for (size_t jt = 250; jt < 260; ++jt) {
+    for (size_t jf = 250; jf < 260; ++jf) {
+      nodes.push_back(MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0,
+                                      nodes.rbegin()[jt], nodes.rbegin()[jf]));
+      RunTest(nodes.back());
+    }
+  }
+}
+
+TEST_F(ProgramTest, JumpReuse) {
+  // As a code size optimization, we try to reuse jumps when possible
+  // instead of emitting new ones. Here we make sure that optimization
+  // is working as intended.
+  //
+  // NOTE: To simplify testing, we rely on implementation details
+  // about what CodeGen::Node values indicate (i.e., vector indices),
+  // but CodeGen users should treat them as opaque values.
+
+  // Populate with 260 initial instruction nodes.
+  std::vector<CodeGen::Node> nodes;
+  nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0));
+  for (size_t i = 1; i < 260; ++i) {
+    nodes.push_back(
+        MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back()));
+  }
+
+  // Branching to nodes[0] and nodes[1] should require 3 new
+  // instructions: two far jumps plus the branch itself.
+  CodeGen::Node one =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0, nodes[0], nodes[1]);
+  EXPECT_EQ(nodes.back() + 3, one);  // XXX: Implementation detail!
+  RunTest(one);
+
+  // Branching again to the same target nodes should require only one
+  // new instruction, as we can reuse the previous branch's jumps.
+  CodeGen::Node two =
+      MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, nodes[0], nodes[1]);
+  EXPECT_EQ(one + 1, two);  // XXX: Implementation detail!
+  RunTest(two);
+}
+
+}  // namespace
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/cons.h b/libchrome/sandbox/linux/bpf_dsl/cons.h
new file mode 100644
index 0000000..07ac3df
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/cons.h
@@ -0,0 +1,137 @@
+// 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 SANDBOX_LINUX_BPF_DSL_CONS_H_
+#define SANDBOX_LINUX_BPF_DSL_CONS_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace cons {
+
+// Namespace cons provides an abstraction for immutable "cons list"
+// data structures as commonly provided in functional programming
+// languages like Lisp or Haskell.
+//
+// A cons list is a linked list consisting of "cells", each of which
+// have a "head" and a "tail" element. A cell's head element contains
+// a user specified value, while the tail element contains a (possibly
+// null) pointer to another cell.
+//
+// An empty list (idiomatically referred to as "nil") can be
+// constructed as "cons::List<Foo>()" or simply as "nullptr" if Foo
+// can be inferred from context (e.g., calling a function that has a
+// "cons::List<Foo>" parameter).
+//
+// Existing lists (including empty lists) can be extended by
+// prepending new values to the front using the "Cons(head, tail)"
+// function, which will allocate a new cons cell. Notably, cons lists
+// support creating multiple lists that share a common tail sequence.
+//
+// Lastly, lists support iteration via C++11's range-based for loop
+// construct.
+//
+// Examples:
+//
+//   // basic construction
+//   const cons::List<char> kNil = nullptr;
+//   cons::List<char> ba = Cons('b', Cons('a', kNil));
+//
+//   // common tail sequence
+//   cons::List<char> cba = Cons('c', ba);
+//   cons::List<char> dba = Cons('d', ba);
+//
+//   // iteration
+//   for (const char& ch : cba) {
+//     // iterates 'c', 'b', 'a'
+//   }
+//   for (const char& ch : dba) {
+//     // iterates 'd', 'b', 'a'
+//   }
+
+// Forward declarations.
+template <typename T>
+class Cell;
+template <typename T>
+class ListIterator;
+
+// List represents a (possibly null) pointer to a cons cell.
+template <typename T>
+using List = std::shared_ptr<const Cell<T>>;
+
+// Cons extends a cons list by prepending a new value to the front.
+template <typename T>
+List<T> Cons(const T& head, List<T> tail) {
+  return std::make_shared<Cell<T>>(head, std::move(tail));
+}
+
+// Cell represents an individual "cons cell" within a cons list.
+template <typename T>
+class Cell {
+ public:
+  Cell(const T& head, List<T> tail) : head_(head), tail_(std::move(tail)) {}
+
+  // Head returns this cell's head element.
+  const T& head() const { return head_; }
+
+  // Tail returns this cell's tail element.
+  const List<T>& tail() const { return tail_; }
+
+ private:
+  T head_;
+  List<T> tail_;
+
+  DISALLOW_COPY_AND_ASSIGN(Cell);
+};
+
+// Begin returns a list iterator pointing to the first element of the
+// cons list. It's provided to support range-based for loops.
+template <typename T>
+ListIterator<T> begin(const List<T>& list) {
+  return ListIterator<T>(list);
+}
+
+// End returns a list iterator pointing to the "past-the-end" element
+// of the cons list (i.e., nil). It's provided to support range-based
+// for loops.
+template <typename T>
+ListIterator<T> end(const List<T>& list) {
+  return ListIterator<T>();
+}
+
+// ListIterator provides C++ forward iterator semantics for traversing
+// a cons list.
+template <typename T>
+class ListIterator {
+ public:
+  ListIterator() : list_() {}
+  explicit ListIterator(const List<T>& list) : list_(list) {}
+
+  const T& operator*() const { return list_->head(); }
+
+  ListIterator& operator++() {
+    list_ = list_->tail();
+    return *this;
+  }
+
+  friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) {
+    return lhs.list_ == rhs.list_;
+  }
+
+ private:
+  List<T> list_;
+};
+
+template <typename T>
+bool operator!=(const ListIterator<T>& lhs, const ListIterator<T>& rhs) {
+  return !(lhs == rhs);
+}
+
+}  // namespace cons
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_CONS_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/dump_bpf.cc b/libchrome/sandbox/linux/bpf_dsl/dump_bpf.cc
new file mode 100644
index 0000000..2edf592
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/dump_bpf.cc
@@ -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.
+
+#include "sandbox/linux/bpf_dsl/dump_bpf.h"
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+const char* AluOpToken(uint32_t code) {
+  switch (BPF_OP(code)) {
+    case BPF_ADD:
+      return "+";
+    case BPF_SUB:
+      return "-";
+    case BPF_MUL:
+      return "*";
+    case BPF_DIV:
+      return "/";
+    case BPF_MOD:
+      return "%";
+    case BPF_OR:
+      return "|";
+    case BPF_XOR:
+      return "^";
+    case BPF_AND:
+      return "&";
+    case BPF_LSH:
+      return "<<";
+    case BPF_RSH:
+      return ">>";
+    default:
+      return "???";
+  }
+}
+
+const char* JmpOpToken(uint32_t code) {
+  switch (BPF_OP(code)) {
+    case BPF_JSET:
+      return "&";
+    case BPF_JEQ:
+      return "==";
+    case BPF_JGE:
+      return ">=";
+    default:
+      return "???";
+  }
+}
+
+const char* DataOffsetName(size_t off) {
+  switch (off) {
+    case SECCOMP_NR_IDX:
+      return "System call number";
+    case SECCOMP_ARCH_IDX:
+      return "Architecture";
+    case SECCOMP_IP_LSB_IDX:
+      return "Instruction pointer (LSB)";
+    case SECCOMP_IP_MSB_IDX:
+      return "Instruction pointer (MSB)";
+    default:
+      return "???";
+  }
+}
+
+void AppendInstruction(std::string* dst, size_t pc, const sock_filter& insn) {
+  base::StringAppendF(dst, "%3zu) ", pc);
+  switch (BPF_CLASS(insn.code)) {
+    case BPF_LD:
+      if (insn.code == BPF_LD + BPF_W + BPF_ABS) {
+        base::StringAppendF(dst, "LOAD %" PRIu32 "  // ", insn.k);
+        size_t maybe_argno =
+            (insn.k - offsetof(struct arch_seccomp_data, args)) /
+            sizeof(uint64_t);
+        if (maybe_argno < 6 && insn.k == SECCOMP_ARG_LSB_IDX(maybe_argno)) {
+          base::StringAppendF(dst, "Argument %zu (LSB)\n", maybe_argno);
+        } else if (maybe_argno < 6 &&
+                   insn.k == SECCOMP_ARG_MSB_IDX(maybe_argno)) {
+          base::StringAppendF(dst, "Argument %zu (MSB)\n", maybe_argno);
+        } else {
+          base::StringAppendF(dst, "%s\n", DataOffsetName(insn.k));
+        }
+      } else {
+        base::StringAppendF(dst, "Load ???\n");
+      }
+      break;
+    case BPF_JMP:
+      if (BPF_OP(insn.code) == BPF_JA) {
+        base::StringAppendF(dst, "JMP %zu\n", pc + insn.k + 1);
+      } else {
+        base::StringAppendF(
+            dst, "if A %s 0x%" PRIx32 "; then JMP %zu else JMP %zu\n",
+            JmpOpToken(insn.code), insn.k, pc + insn.jt + 1, pc + insn.jf + 1);
+      }
+      break;
+    case BPF_RET:
+      base::StringAppendF(dst, "RET 0x%" PRIx32 "  // ", insn.k);
+      if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP) {
+        base::StringAppendF(dst, "Trap #%" PRIu32 "\n",
+                            insn.k & SECCOMP_RET_DATA);
+      } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
+        base::StringAppendF(dst, "errno = %" PRIu32 "\n",
+                            insn.k & SECCOMP_RET_DATA);
+      } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
+        base::StringAppendF(dst, "Trace #%" PRIu32 "\n",
+                            insn.k & SECCOMP_RET_DATA);
+      } else if (insn.k == SECCOMP_RET_ALLOW) {
+        base::StringAppendF(dst, "Allowed\n");
+      } else if (insn.k == SECCOMP_RET_KILL) {
+        base::StringAppendF(dst, "Kill\n");
+      } else {
+        base::StringAppendF(dst, "???\n");
+      }
+      break;
+    case BPF_ALU:
+      if (BPF_OP(insn.code) == BPF_NEG) {
+        base::StringAppendF(dst, "A := -A\n");
+      } else {
+        base::StringAppendF(dst, "A := A %s 0x%" PRIx32 "\n",
+                            AluOpToken(insn.code), insn.k);
+      }
+      break;
+    default:
+      base::StringAppendF(dst, "???\n");
+      break;
+  }
+}
+
+}  // namespace
+
+void DumpBPF::PrintProgram(const CodeGen::Program& program) {
+  fputs(StringPrintProgram(program).c_str(), stderr);
+}
+
+std::string DumpBPF::StringPrintProgram(const CodeGen::Program& program) {
+  std::string res;
+  for (size_t i = 0; i < program.size(); i++) {
+    AppendInstruction(&res, i + 1, program[i]);
+  }
+  return res;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/dump_bpf.h b/libchrome/sandbox/linux/bpf_dsl/dump_bpf.h
new file mode 100644
index 0000000..a7db589
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/dump_bpf.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.
+
+#include <string>
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+class SANDBOX_EXPORT DumpBPF {
+ public:
+  // PrintProgram writes |program| in a human-readable format to stderr.
+  static void PrintProgram(const CodeGen::Program& program);
+
+  // StringPrintProgram writes |program| in a human-readable format to
+  // a std::string.
+  static std::string StringPrintProgram(const CodeGen::Program& program);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/errorcode.h b/libchrome/sandbox/linux/bpf_dsl/errorcode.h
new file mode 100644
index 0000000..611c27d
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/errorcode.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 SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
+#define SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// TODO(mdempsky): Find a proper home for ERR_{MIN,MAX}_ERRNO and
+// remove this header.
+class SANDBOX_EXPORT ErrorCode {
+ public:
+  enum {
+    ERR_MIN_ERRNO = 0,
+#if defined(__mips__)
+    // MIPS only supports errno up to 1133
+    ERR_MAX_ERRNO = 1133,
+#else
+    // TODO(markus): Android only supports errno up to 255
+    // (crbug.com/181647).
+    ERR_MAX_ERRNO = 4095,
+#endif
+  };
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ErrorCode);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
diff --git a/libchrome/sandbox/linux/bpf_dsl/linux_syscall_ranges.h b/libchrome/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
new file mode 100644
index 0000000..a747770
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
+#define SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
+
+#if defined(__x86_64__)
+
+#define MIN_SYSCALL         0u
+#define MAX_PUBLIC_SYSCALL  1024u
+#define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
+
+#elif defined(__i386__)
+
+#define MIN_SYSCALL         0u
+#define MAX_PUBLIC_SYSCALL  1024u
+#define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
+
+#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
+
+// ARM EABI includes "ARM private" system calls starting at |__ARM_NR_BASE|,
+// and a "ghost syscall private to the kernel", cmpxchg,
+// at |__ARM_NR_BASE+0x00fff0|.
+// See </arch/arm/include/asm/unistd.h> in the Linux kernel.
+
+// __NR_SYSCALL_BASE is 0 in thumb and ARM EABI.
+#define MIN_SYSCALL         0u
+#define MAX_PUBLIC_SYSCALL  (MIN_SYSCALL + 1024u)
+// __ARM_NR_BASE is __NR_SYSCALL_BASE + 0xf0000u
+#define MIN_PRIVATE_SYSCALL 0xf0000u
+#define MAX_PRIVATE_SYSCALL (MIN_PRIVATE_SYSCALL + 16u)
+#define MIN_GHOST_SYSCALL   (MIN_PRIVATE_SYSCALL + 0xfff0u)
+#define MAX_SYSCALL         (MIN_GHOST_SYSCALL + 4u)
+
+#elif defined(__mips__) && (_MIPS_SIM == _ABIO32)
+
+#include <asm/unistd.h>  // for __NR_O32_Linux and __NR_Linux_syscalls
+#define MIN_SYSCALL         __NR_O32_Linux
+#define MAX_PUBLIC_SYSCALL  (MIN_SYSCALL + __NR_Linux_syscalls)
+#define MAX_SYSCALL         MAX_PUBLIC_SYSCALL
+
+#elif defined(__mips__) && (_MIPS_SIM == _ABI64)
+
+#error "Add support to header file"
+
+#elif defined(__aarch64__)
+
+#define MIN_SYSCALL 0u
+#define MAX_PUBLIC_SYSCALL 279u
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+
+#else
+#error "Unsupported architecture"
+#endif
+
+#endif  // SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/policy.cc b/libchrome/sandbox/linux/bpf_dsl/policy.cc
new file mode 100644
index 0000000..c20edc6
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/policy.cc
@@ -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.
+
+#include "sandbox/linux/bpf_dsl/policy.h"
+
+#include <errno.h>
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+ResultExpr Policy::InvalidSyscall() const {
+  return Error(ENOSYS);
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/policy.h b/libchrome/sandbox/linux/bpf_dsl/policy.h
new file mode 100644
index 0000000..6c67589
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/policy.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_H_
+#define SANDBOX_LINUX_BPF_DSL_POLICY_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// Interface to implement to define a BPF sandbox policy.
+class SANDBOX_EXPORT Policy {
+ public:
+  Policy() {}
+  virtual ~Policy() {}
+
+  // User extension point for writing custom sandbox policies.
+  // The returned ResultExpr will control how the kernel responds to the
+  // specified system call number.
+  virtual ResultExpr EvaluateSyscall(int sysno) const = 0;
+
+  // Optional overload for specifying alternate behavior for invalid
+  // system calls.  The default is to return ENOSYS.
+  virtual ResultExpr InvalidSyscall() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Policy);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_POLICY_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/policy_compiler.cc b/libchrome/sandbox/linux/bpf_dsl/policy_compiler.cc
new file mode 100644
index 0000000..7ce517a
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -0,0 +1,466 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+#if defined(__i386__) || defined(__x86_64__)
+const bool kIsIntel = true;
+#else
+const bool kIsIntel = false;
+#endif
+#if defined(__x86_64__) && defined(__ILP32__)
+const bool kIsX32 = true;
+#else
+const bool kIsX32 = false;
+#endif
+
+const int kSyscallsRequiredForUnsafeTraps[] = {
+    __NR_rt_sigprocmask,
+    __NR_rt_sigreturn,
+#if defined(__NR_sigprocmask)
+    __NR_sigprocmask,
+#endif
+#if defined(__NR_sigreturn)
+    __NR_sigreturn,
+#endif
+};
+
+bool HasExactlyOneBit(uint64_t x) {
+  // Common trick; e.g., see http://stackoverflow.com/a/108329.
+  return x != 0 && (x & (x - 1)) == 0;
+}
+
+ResultExpr DefaultPanic(const char* error) {
+  return Kill();
+}
+
+// A Trap() handler that returns an "errno" value. The value is encoded
+// in the "aux" parameter.
+intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) {
+  // TrapFnc functions report error by following the native kernel convention
+  // of returning an exit code in the range of -1..-4096. They do not try to
+  // set errno themselves. The glibc wrapper that triggered the SIGSYS will
+  // ultimately do so for us.
+  int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA;
+  return -err;
+}
+
+bool HasUnsafeTraps(const Policy* policy) {
+  DCHECK(policy);
+  for (uint32_t sysnum : SyscallSet::ValidOnly()) {
+    if (policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) {
+      return true;
+    }
+  }
+  return policy->InvalidSyscall()->HasUnsafeTraps();
+}
+
+}  // namespace
+
+struct PolicyCompiler::Range {
+  uint32_t from;
+  CodeGen::Node node;
+};
+
+PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry)
+    : policy_(policy),
+      registry_(registry),
+      escapepc_(0),
+      panic_func_(DefaultPanic),
+      gen_(),
+      has_unsafe_traps_(HasUnsafeTraps(policy_)) {
+  DCHECK(policy);
+}
+
+PolicyCompiler::~PolicyCompiler() {
+}
+
+CodeGen::Program PolicyCompiler::Compile() {
+  CHECK(policy_->InvalidSyscall()->IsDeny())
+      << "Policies should deny invalid system calls";
+
+  // If our BPF program has unsafe traps, enable support for them.
+  if (has_unsafe_traps_) {
+    CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC";
+
+    for (int sysnum : kSyscallsRequiredForUnsafeTraps) {
+      CHECK(policy_->EvaluateSyscall(sysnum)->IsAllow())
+          << "Policies that use UnsafeTrap() must unconditionally allow all "
+             "required system calls";
+    }
+
+    CHECK(registry_->EnableUnsafeTraps())
+        << "We'd rather die than enable unsafe traps";
+  }
+
+  // Assemble the BPF filter program.
+  return gen_.Compile(AssemblePolicy());
+}
+
+void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) {
+  escapepc_ = escapepc;
+}
+
+void PolicyCompiler::SetPanicFunc(PanicFunc panic_func) {
+  panic_func_ = panic_func;
+}
+
+CodeGen::Node PolicyCompiler::AssemblePolicy() {
+  // A compiled policy consists of three logical parts:
+  //   1. Check that the "arch" field matches the expected architecture.
+  //   2. If the policy involves unsafe traps, check if the syscall was
+  //      invoked by Syscall::Call, and then allow it unconditionally.
+  //   3. Check the system call number and jump to the appropriate compiled
+  //      system call policy number.
+  return CheckArch(MaybeAddEscapeHatch(DispatchSyscall()));
+}
+
+CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) {
+  // If the architecture doesn't match SECCOMP_ARCH, disallow the
+  // system call.
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX,
+      gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed,
+                           CompileResult(panic_func_(
+                               "Invalid audit architecture in BPF filter"))));
+}
+
+CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
+  // If no unsafe traps, then simply return |rest|.
+  if (!has_unsafe_traps_) {
+    return rest;
+  }
+
+  // We already enabled unsafe traps in Compile, but enable them again to give
+  // the trap registry a second chance to complain before we add the backdoor.
+  CHECK(registry_->EnableUnsafeTraps());
+
+  // Allow system calls, if they originate from our magic return address.
+  const uint32_t lopc = static_cast<uint32_t>(escapepc_);
+  const uint32_t hipc = static_cast<uint32_t>(escapepc_ >> 32);
+
+  // BPF cannot do native 64-bit comparisons, so we have to compare
+  // both 32-bit halves of the instruction pointer. If they match what
+  // we expect, we return ERR_ALLOWED. If either or both don't match,
+  // we continue evalutating the rest of the sandbox policy.
+  //
+  // For simplicity, we check the full 64-bit instruction pointer even
+  // on 32-bit architectures.
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX,
+      gen_.MakeInstruction(
+          BPF_JMP + BPF_JEQ + BPF_K, lopc,
+          gen_.MakeInstruction(
+              BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX,
+              gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hipc,
+                                   CompileResult(Allow()), rest)),
+          rest));
+}
+
+CodeGen::Node PolicyCompiler::DispatchSyscall() {
+  // Evaluate all possible system calls and group their Nodes into
+  // ranges of identical codes.
+  Ranges ranges;
+  FindRanges(&ranges);
+
+  // Compile the system call ranges to an optimized BPF jumptable
+  CodeGen::Node jumptable = AssembleJumpTable(ranges.begin(), ranges.end());
+
+  // Grab the system call number, so that we can check it and then
+  // execute the jump table.
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable));
+}
+
+CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) {
+  if (kIsIntel) {
+    // On Intel architectures, verify that system call numbers are in the
+    // expected number range.
+    CodeGen::Node invalidX32 =
+        CompileResult(panic_func_("Illegal mixing of system call ABIs"));
+    if (kIsX32) {
+      // The newer x32 API always sets bit 30.
+      return gen_.MakeInstruction(
+          BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32);
+    } else {
+      // The older i386 and x86-64 APIs clear bit 30 on all system calls.
+      return gen_.MakeInstruction(
+          BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed);
+    }
+  }
+
+  // TODO(mdempsky): Similar validation for other architectures?
+  return passed;
+}
+
+void PolicyCompiler::FindRanges(Ranges* ranges) {
+  // Please note that "struct seccomp_data" defines system calls as a signed
+  // int32_t, but BPF instructions always operate on unsigned quantities. We
+  // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
+  // and then verifying that the rest of the number range (both positive and
+  // negative) all return the same Node.
+  const CodeGen::Node invalid_node = CompileResult(policy_->InvalidSyscall());
+  uint32_t old_sysnum = 0;
+  CodeGen::Node old_node =
+      SyscallSet::IsValid(old_sysnum)
+          ? CompileResult(policy_->EvaluateSyscall(old_sysnum))
+          : invalid_node;
+
+  for (uint32_t sysnum : SyscallSet::All()) {
+    CodeGen::Node node =
+        SyscallSet::IsValid(sysnum)
+            ? CompileResult(policy_->EvaluateSyscall(static_cast<int>(sysnum)))
+            : invalid_node;
+    // N.B., here we rely on CodeGen folding (i.e., returning the same
+    // node value for) identical code sequences, otherwise our jump
+    // table will blow up in size.
+    if (node != old_node) {
+      ranges->push_back(Range{old_sysnum, old_node});
+      old_sysnum = sysnum;
+      old_node = node;
+    }
+  }
+  ranges->push_back(Range{old_sysnum, old_node});
+}
+
+CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
+                                                Ranges::const_iterator stop) {
+  // We convert the list of system call ranges into jump table that performs
+  // a binary search over the ranges.
+  // As a sanity check, we need to have at least one distinct ranges for us
+  // to be able to build a jump table.
+  CHECK(start < stop) << "Invalid iterator range";
+  const auto n = stop - start;
+  if (n == 1) {
+    // If we have narrowed things down to a single range object, we can
+    // return from the BPF filter program.
+    return start->node;
+  }
+
+  // Pick the range object that is located at the mid point of our list.
+  // We compare our system call number against the lowest valid system call
+  // number in this range object. If our number is lower, it is outside of
+  // this range object. If it is greater or equal, it might be inside.
+  Ranges::const_iterator mid = start + n / 2;
+
+  // Sub-divide the list of ranges and continue recursively.
+  CodeGen::Node jf = AssembleJumpTable(start, mid);
+  CodeGen::Node jt = AssembleJumpTable(mid, stop);
+  return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf);
+}
+
+CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) {
+  return res->Compile(this);
+}
+
+CodeGen::Node PolicyCompiler::MaskedEqual(int argno,
+                                          size_t width,
+                                          uint64_t mask,
+                                          uint64_t value,
+                                          CodeGen::Node passed,
+                                          CodeGen::Node failed) {
+  // Sanity check that arguments make sense.
+  CHECK(argno >= 0 && argno < 6) << "Invalid argument number " << argno;
+  CHECK(width == 4 || width == 8) << "Invalid argument width " << width;
+  CHECK_NE(0U, mask) << "Zero mask is invalid";
+  CHECK_EQ(value, value & mask) << "Value contains masked out bits";
+  if (sizeof(void*) == 4) {
+    CHECK_EQ(4U, width) << "Invalid width on 32-bit platform";
+  }
+  if (width == 4) {
+    CHECK_EQ(0U, mask >> 32) << "Mask exceeds argument size";
+    CHECK_EQ(0U, value >> 32) << "Value exceeds argument size";
+  }
+
+  // We want to emit code to check "(arg & mask) == value" where arg, mask, and
+  // value are 64-bit values, but the BPF machine is only 32-bit. We implement
+  // this by independently testing the upper and lower 32-bits and continuing to
+  // |passed| if both evaluate true, or to |failed| if either evaluate false.
+  return MaskedEqualHalf(argno, width, mask, value, ArgHalf::UPPER,
+                         MaskedEqualHalf(argno, width, mask, value,
+                                         ArgHalf::LOWER, passed, failed),
+                         failed);
+}
+
+CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno,
+                                              size_t width,
+                                              uint64_t full_mask,
+                                              uint64_t full_value,
+                                              ArgHalf half,
+                                              CodeGen::Node passed,
+                                              CodeGen::Node failed) {
+  if (width == 4 && half == ArgHalf::UPPER) {
+    // Special logic for sanity checking the upper 32-bits of 32-bit system
+    // call arguments.
+
+    // TODO(mdempsky): Compile Unexpected64bitArgument() just per program.
+    CodeGen::Node invalid_64bit = Unexpected64bitArgument();
+
+    const uint32_t upper = SECCOMP_ARG_MSB_IDX(argno);
+    const uint32_t lower = SECCOMP_ARG_LSB_IDX(argno);
+
+    if (sizeof(void*) == 4) {
+      // On 32-bit platforms, the upper 32-bits should always be 0:
+      //   LDW  [upper]
+      //   JEQ  0, passed, invalid
+      return gen_.MakeInstruction(
+          BPF_LD + BPF_W + BPF_ABS,
+          upper,
+          gen_.MakeInstruction(
+              BPF_JMP + BPF_JEQ + BPF_K, 0, passed, invalid_64bit));
+    }
+
+    // On 64-bit platforms, the upper 32-bits may be 0 or ~0; but we only allow
+    // ~0 if the sign bit of the lower 32-bits is set too:
+    //   LDW  [upper]
+    //   JEQ  0, passed, (next)
+    //   JEQ  ~0, (next), invalid
+    //   LDW  [lower]
+    //   JSET (1<<31), passed, invalid
+    //
+    // TODO(mdempsky): The JSET instruction could perhaps jump to passed->next
+    // instead, as the first instruction of passed should be "LDW [lower]".
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        upper,
+        gen_.MakeInstruction(
+            BPF_JMP + BPF_JEQ + BPF_K,
+            0,
+            passed,
+            gen_.MakeInstruction(
+                BPF_JMP + BPF_JEQ + BPF_K,
+                std::numeric_limits<uint32_t>::max(),
+                gen_.MakeInstruction(
+                    BPF_LD + BPF_W + BPF_ABS,
+                    lower,
+                    gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K,
+                                         1U << 31,
+                                         passed,
+                                         invalid_64bit)),
+                invalid_64bit)));
+  }
+
+  const uint32_t idx = (half == ArgHalf::UPPER) ? SECCOMP_ARG_MSB_IDX(argno)
+                                                : SECCOMP_ARG_LSB_IDX(argno);
+  const uint32_t mask = (half == ArgHalf::UPPER) ? full_mask >> 32 : full_mask;
+  const uint32_t value =
+      (half == ArgHalf::UPPER) ? full_value >> 32 : full_value;
+
+  // Emit a suitable instruction sequence for (arg & mask) == value.
+
+  // For (arg & 0) == 0, just return passed.
+  if (mask == 0) {
+    CHECK_EQ(0U, value);
+    return passed;
+  }
+
+  // For (arg & ~0) == value, emit:
+  //   LDW  [idx]
+  //   JEQ  value, passed, failed
+  if (mask == std::numeric_limits<uint32_t>::max()) {
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        idx,
+        gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed));
+  }
+
+  // For (arg & mask) == 0, emit:
+  //   LDW  [idx]
+  //   JSET mask, failed, passed
+  // (Note: failed and passed are intentionally swapped.)
+  if (value == 0) {
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        idx,
+        gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, failed, passed));
+  }
+
+  // For (arg & x) == x where x is a single-bit value, emit:
+  //   LDW  [idx]
+  //   JSET mask, passed, failed
+  if (mask == value && HasExactlyOneBit(mask)) {
+    return gen_.MakeInstruction(
+        BPF_LD + BPF_W + BPF_ABS,
+        idx,
+        gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, passed, failed));
+  }
+
+  // Generic fallback:
+  //   LDW  [idx]
+  //   AND  mask
+  //   JEQ  value, passed, failed
+  return gen_.MakeInstruction(
+      BPF_LD + BPF_W + BPF_ABS,
+      idx,
+      gen_.MakeInstruction(
+          BPF_ALU + BPF_AND + BPF_K,
+          mask,
+          gen_.MakeInstruction(
+              BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed)));
+}
+
+CodeGen::Node PolicyCompiler::Unexpected64bitArgument() {
+  return CompileResult(panic_func_("Unexpected 64bit argument detected"));
+}
+
+CodeGen::Node PolicyCompiler::Return(uint32_t ret) {
+  if (has_unsafe_traps_ && (ret & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
+    // When inside an UnsafeTrap() callback, we want to allow all system calls.
+    // This means, we must conditionally disable the sandbox -- and that's not
+    // something that kernel-side BPF filters can do, as they cannot inspect
+    // any state other than the syscall arguments.
+    // But if we redirect all error handlers to user-space, then we can easily
+    // make this decision.
+    // The performance penalty for this extra round-trip to user-space is not
+    // actually that bad, as we only ever pay it for denied system calls; and a
+    // typical program has very few of these.
+    return Trap(ReturnErrno, reinterpret_cast<void*>(ret & SECCOMP_RET_DATA),
+                true);
+  }
+
+  return gen_.MakeInstruction(BPF_RET + BPF_K, ret);
+}
+
+CodeGen::Node PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc,
+                                   const void* aux,
+                                   bool safe) {
+  uint16_t trap_id = registry_->Add(fnc, aux, safe);
+  return gen_.MakeInstruction(BPF_RET + BPF_K, SECCOMP_RET_TRAP + trap_id);
+}
+
+bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) {
+  for (size_t i = 0; i < arraysize(kSyscallsRequiredForUnsafeTraps); ++i) {
+    if (sysno == kSyscallsRequiredForUnsafeTraps[i]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/policy_compiler.h b/libchrome/sandbox/linux/bpf_dsl/policy_compiler.h
new file mode 100644
index 0000000..48b1d78
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/policy_compiler.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 SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
+#define SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class Policy;
+
+// PolicyCompiler implements the bpf_dsl compiler, allowing users to
+// transform bpf_dsl policies into BPF programs to be executed by the
+// Linux kernel.
+class SANDBOX_EXPORT PolicyCompiler {
+ public:
+  using PanicFunc = bpf_dsl::ResultExpr (*)(const char* error);
+
+  PolicyCompiler(const Policy* policy, TrapRegistry* registry);
+  ~PolicyCompiler();
+
+  // Compile registers any trap handlers needed by the policy and
+  // compiles the policy to a BPF program, which it returns.
+  CodeGen::Program Compile();
+
+  // DangerousSetEscapePC sets the "escape PC" that is allowed to issue any
+  // system calls, regardless of policy.
+  void DangerousSetEscapePC(uint64_t escapepc);
+
+  // SetPanicFunc sets the callback function used for handling faulty
+  // system call conditions.  The default behavior is to immediately kill
+  // the process.
+  // TODO(mdempsky): Move this into Policy?
+  void SetPanicFunc(PanicFunc panic_func);
+
+  // UnsafeTraps require some syscalls to always be allowed.
+  // This helper function returns true for these calls.
+  static bool IsRequiredForUnsafeTrap(int sysno);
+
+  // Functions below are meant for use within bpf_dsl itself.
+
+  // Return returns a CodeGen::Node that returns the specified seccomp
+  // return value.
+  CodeGen::Node Return(uint32_t ret);
+
+  // Trap returns a CodeGen::Node to indicate the system call should
+  // instead invoke a trap handler.
+  CodeGen::Node Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
+
+  // MaskedEqual returns a CodeGen::Node that represents a conditional branch.
+  // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
+  // to "value"; if equal, then "passed" will be executed, otherwise "failed".
+  // If "width" is 4, the argument must in the range of 0x0..(1u << 32 - 1)
+  // If it is outside this range, the sandbox treats the system call just
+  // the same as any other ABI violation (i.e., it panics).
+  CodeGen::Node MaskedEqual(int argno,
+                            size_t width,
+                            uint64_t mask,
+                            uint64_t value,
+                            CodeGen::Node passed,
+                            CodeGen::Node failed);
+
+ private:
+  struct Range;
+  typedef std::vector<Range> Ranges;
+
+  // Used by MaskedEqualHalf to track which half of the argument it's
+  // emitting instructions for.
+  enum class ArgHalf {
+    LOWER,
+    UPPER,
+  };
+
+  // Compile the configured policy into a complete instruction sequence.
+  CodeGen::Node AssemblePolicy();
+
+  // Return an instruction sequence that checks the
+  // arch_seccomp_data's "arch" field is valid, and then passes
+  // control to |passed| if so.
+  CodeGen::Node CheckArch(CodeGen::Node passed);
+
+  // If |has_unsafe_traps_| is true, returns an instruction sequence
+  // that allows all system calls from |escapepc_|, and otherwise
+  // passes control to |rest|. Otherwise, simply returns |rest|.
+  CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest);
+
+  // Return an instruction sequence that loads and checks the system
+  // call number, performs a binary search, and then dispatches to an
+  // appropriate instruction sequence compiled from the current
+  // policy.
+  CodeGen::Node DispatchSyscall();
+
+  // Return an instruction sequence that checks the system call number
+  // (expected to be loaded in register A) and if valid, passes
+  // control to |passed| (with register A still valid).
+  CodeGen::Node CheckSyscallNumber(CodeGen::Node passed);
+
+  // Finds all the ranges of system calls that need to be handled. Ranges are
+  // sorted in ascending order of system call numbers. There are no gaps in the
+  // ranges. System calls with identical CodeGen::Nodes are coalesced into a
+  // single
+  // range.
+  void FindRanges(Ranges* ranges);
+
+  // Returns a BPF program snippet that implements a jump table for the
+  // given range of system call numbers. This function runs recursively.
+  CodeGen::Node AssembleJumpTable(Ranges::const_iterator start,
+                                  Ranges::const_iterator stop);
+
+  // CompileResult compiles an individual result expression into a
+  // CodeGen node.
+  CodeGen::Node CompileResult(const ResultExpr& res);
+
+  // Returns a BPF program that evaluates half of a conditional expression;
+  // it should only ever be called from CondExpression().
+  CodeGen::Node MaskedEqualHalf(int argno,
+                                size_t width,
+                                uint64_t full_mask,
+                                uint64_t full_value,
+                                ArgHalf half,
+                                CodeGen::Node passed,
+                                CodeGen::Node failed);
+
+  // Returns the fatal CodeGen::Node that is used to indicate that somebody
+  // attempted to pass a 64bit value in a 32bit system call argument.
+  CodeGen::Node Unexpected64bitArgument();
+
+  const Policy* policy_;
+  TrapRegistry* registry_;
+  uint64_t escapepc_;
+  PanicFunc panic_func_;
+
+  CodeGen gen_;
+  bool has_unsafe_traps_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyCompiler);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/seccomp_macros.h b/libchrome/sandbox/linux/bpf_dsl/seccomp_macros.h
new file mode 100644
index 0000000..af70f21
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
+#define SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
+
+#include <sys/types.h>  // For __BIONIC__.
+// Old Bionic versions do not have sys/user.h.  The if can be removed once we no
+// longer need to support these old Bionic versions.
+// All x86_64 builds use a new enough bionic to have sys/user.h.
+#if !defined(__BIONIC__) || defined(__x86_64__)
+#if !defined(__native_client_nonsfi__)
+#include <sys/user.h>
+#endif
+#if defined(__mips__)
+// sys/user.h in eglibc misses size_t definition
+#include <stddef.h>
+#endif
+#endif
+
+#include "sandbox/linux/system_headers/linux_seccomp.h"  // For AUDIT_ARCH_*
+
+// Impose some reasonable maximum BPF program size. Realistically, the
+// kernel probably has much lower limits. But by limiting to less than
+// 30 bits, we can ease requirements on some of our data types.
+#define SECCOMP_MAX_PROGRAM_SIZE (1<<30)
+
+#if defined(__i386__)
+#define SECCOMP_ARCH        AUDIT_ARCH_I386
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, REG_EAX)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, REG_EAX)
+#define SECCOMP_IP(_ctx)        SECCOMP_REG(_ctx, REG_EIP)
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, REG_EBX)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, REG_ECX)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, REG_EDX)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, REG_ESI)
+#define SECCOMP_PARM5(_ctx)     SECCOMP_REG(_ctx, REG_EDI)
+#define SECCOMP_PARM6(_ctx)     SECCOMP_REG(_ctx, REG_EBP)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly.  This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
+struct regs_struct {
+  long int ebx;
+  long int ecx;
+  long int edx;
+  long int esi;
+  long int edi;
+  long int ebp;
+  long int eax;
+  long int xds;
+  long int xes;
+  long int xfs;
+  long int xgs;
+  long int orig_eax;
+  long int eip;
+  long int xcs;
+  long int eflags;
+  long int esp;
+  long int xss;
+};
+#else
+typedef user_regs_struct regs_struct;
+#endif
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).eax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_eax
+#define SECCOMP_PT_IP(_regs)      (_regs).eip
+#define SECCOMP_PT_PARM1(_regs)   (_regs).ebx
+#define SECCOMP_PT_PARM2(_regs)   (_regs).ecx
+#define SECCOMP_PT_PARM3(_regs)   (_regs).edx
+#define SECCOMP_PT_PARM4(_regs)   (_regs).esi
+#define SECCOMP_PT_PARM5(_regs)   (_regs).edi
+#define SECCOMP_PT_PARM6(_regs)   (_regs).ebp
+
+#elif defined(__x86_64__)
+#define SECCOMP_ARCH        AUDIT_ARCH_X86_64
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, REG_RAX)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, REG_RAX)
+#define SECCOMP_IP(_ctx)        SECCOMP_REG(_ctx, REG_RIP)
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, REG_RDI)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, REG_RSI)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, REG_RDX)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, REG_R10)
+#define SECCOMP_PARM5(_ctx)     SECCOMP_REG(_ctx, REG_R8)
+#define SECCOMP_PARM6(_ctx)     SECCOMP_REG(_ctx, REG_R9)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+typedef user_regs_struct regs_struct;
+#define SECCOMP_PT_RESULT(_regs)  (_regs).rax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_rax
+#define SECCOMP_PT_IP(_regs)      (_regs).rip
+#define SECCOMP_PT_PARM1(_regs)   (_regs).rdi
+#define SECCOMP_PT_PARM2(_regs)   (_regs).rsi
+#define SECCOMP_PT_PARM3(_regs)   (_regs).rdx
+#define SECCOMP_PT_PARM4(_regs)   (_regs).r10
+#define SECCOMP_PT_PARM5(_regs)   (_regs).r8
+#define SECCOMP_PT_PARM6(_regs)   (_regs).r9
+
+#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
+#define SECCOMP_ARCH AUDIT_ARCH_ARM
+
+// ARM sigcontext_t is different from i386/x86_64.
+// See </arch/arm/include/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.arm_##_reg)
+// ARM EABI syscall convention.
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, r0)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, r7)
+#define SECCOMP_IP(_ctx)        SECCOMP_REG(_ctx, pc)
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, r0)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, r1)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, r2)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, r3)
+#define SECCOMP_PARM5(_ctx)     SECCOMP_REG(_ctx, r4)
+#define SECCOMP_PARM6(_ctx)     SECCOMP_REG(_ctx, r5)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly.  This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
+struct regs_struct {
+  unsigned long uregs[18];
+};
+#else
+typedef user_regs regs_struct;
+#endif
+
+#define REG_cpsr    uregs[16]
+#define REG_pc      uregs[15]
+#define REG_lr      uregs[14]
+#define REG_sp      uregs[13]
+#define REG_ip      uregs[12]
+#define REG_fp      uregs[11]
+#define REG_r10     uregs[10]
+#define REG_r9      uregs[9]
+#define REG_r8      uregs[8]
+#define REG_r7      uregs[7]
+#define REG_r6      uregs[6]
+#define REG_r5      uregs[5]
+#define REG_r4      uregs[4]
+#define REG_r3      uregs[3]
+#define REG_r2      uregs[2]
+#define REG_r1      uregs[1]
+#define REG_r0      uregs[0]
+#define REG_ORIG_r0 uregs[17]
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).REG_r0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_r7
+#define SECCOMP_PT_IP(_regs)      (_regs).REG_pc
+#define SECCOMP_PT_PARM1(_regs)   (_regs).REG_r0
+#define SECCOMP_PT_PARM2(_regs)   (_regs).REG_r1
+#define SECCOMP_PT_PARM3(_regs)   (_regs).REG_r2
+#define SECCOMP_PT_PARM4(_regs)   (_regs).REG_r3
+#define SECCOMP_PT_PARM5(_regs)   (_regs).REG_r4
+#define SECCOMP_PT_PARM6(_regs)   (_regs).REG_r5
+
+#elif defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+#define SECCOMP_ARCH        AUDIT_ARCH_MIPSEL
+#define SYSCALL_EIGHT_ARGS
+// MIPS sigcontext_t is different from i386/x86_64 and ARM.
+// See </arch/mips/include/uapi/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[_reg])
+// Based on MIPS o32 ABI syscall convention.
+// On MIPS, when indirect syscall is being made (syscall(__NR_foo)),
+// real identificator (__NR_foo) is not in v0, but in a0
+#define SECCOMP_RESULT(_ctx)    SECCOMP_REG(_ctx, 2)
+#define SECCOMP_SYSCALL(_ctx)   SECCOMP_REG(_ctx, 2)
+#define SECCOMP_IP(_ctx)        (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx)     SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM2(_ctx)     SECCOMP_REG(_ctx, 5)
+#define SECCOMP_PARM3(_ctx)     SECCOMP_REG(_ctx, 6)
+#define SECCOMP_PARM4(_ctx)     SECCOMP_REG(_ctx, 7)
+// Only the first 4 arguments of syscall are in registers.
+// The rest are on the stack.
+#define SECCOMP_STACKPARM(_ctx, n)  (((long *)SECCOMP_REG(_ctx, 29))[(n)])
+#define SECCOMP_PARM5(_ctx)         SECCOMP_STACKPARM(_ctx, 4)
+#define SECCOMP_PARM6(_ctx)         SECCOMP_STACKPARM(_ctx, 5)
+#define SECCOMP_PARM7(_ctx)         SECCOMP_STACKPARM(_ctx, 6)
+#define SECCOMP_PARM8(_ctx)         SECCOMP_STACKPARM(_ctx, 7)
+#define SECCOMP_NR_IDX          (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX        (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX      (offsetof(struct arch_seccomp_data,           \
+                                          instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) +   \
+                                 8*(nr) + 0)
+
+// On Mips we don't have structures like user_regs or user_regs_struct in
+// sys/user.h that we could use, so we just define regs_struct directly.
+struct regs_struct {
+  unsigned long long regs[32];
+};
+
+#define REG_a3 regs[7]
+#define REG_a2 regs[6]
+#define REG_a1 regs[5]
+#define REG_a0 regs[4]
+#define REG_v1 regs[3]
+#define REG_v0 regs[2]
+
+#define SECCOMP_PT_RESULT(_regs)  (_regs).REG_v0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_v0
+#define SECCOMP_PT_PARM1(_regs)   (_regs).REG_a0
+#define SECCOMP_PT_PARM2(_regs)   (_regs).REG_a1
+#define SECCOMP_PT_PARM3(_regs)   (_regs).REG_a2
+#define SECCOMP_PT_PARM4(_regs)   (_regs).REG_a3
+
+#elif defined(__aarch64__)
+struct regs_struct {
+  unsigned long long regs[31];
+  unsigned long long sp;
+  unsigned long long pc;
+  unsigned long long pstate;
+};
+
+#define SECCOMP_ARCH AUDIT_ARCH_AARCH64
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.regs[_reg])
+
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 0)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 8)
+#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 0)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 1)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 3)
+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, 5)
+
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX \
+  (offsetof(struct arch_seccomp_data, instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX \
+  (offsetof(struct arch_seccomp_data, instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) \
+  (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) \
+  (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0)
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).regs[0]
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).regs[8]
+#define SECCOMP_PT_IP(_regs) (_regs).pc
+#define SECCOMP_PT_PARM1(_regs) (_regs).regs[0]
+#define SECCOMP_PT_PARM2(_regs) (_regs).regs[1]
+#define SECCOMP_PT_PARM3(_regs) (_regs).regs[2]
+#define SECCOMP_PT_PARM4(_regs) (_regs).regs[3]
+#define SECCOMP_PT_PARM5(_regs) (_regs).regs[4]
+#define SECCOMP_PT_PARM6(_regs) (_regs).regs[5]
+#else
+#error Unsupported target platform
+
+#endif
+
+#endif  // SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/syscall_set.cc b/libchrome/sandbox/linux/bpf_dsl/syscall_set.cc
new file mode 100644
index 0000000..3d61fa3
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/syscall_set.cc
@@ -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.
+
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
+
+namespace sandbox {
+
+namespace {
+
+#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+// This is true for Mips O32 ABI.
+static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 4000");
+#else
+// This true for supported architectures (Intel and ARM EABI).
+static_assert(MIN_SYSCALL == 0u,
+              "min syscall should always be zero");
+#endif
+
+// SyscallRange represents an inclusive range of system call numbers.
+struct SyscallRange {
+  uint32_t first;
+  uint32_t last;
+};
+
+const SyscallRange kValidSyscallRanges[] = {
+    // First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL
+    // on Intel architectures, but leaves room for private syscalls on ARM.
+    {MIN_SYSCALL, MAX_PUBLIC_SYSCALL},
+#if defined(__arm__)
+    // ARM EABI includes "ARM private" system calls starting at
+    // MIN_PRIVATE_SYSCALL, and a "ghost syscall private to the kernel" at
+    // MIN_GHOST_SYSCALL.
+    {MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL},
+    {MIN_GHOST_SYSCALL, MAX_SYSCALL},
+#endif
+};
+
+}  // namespace
+
+SyscallSet::Iterator SyscallSet::begin() const {
+  return Iterator(set_, false);
+}
+
+SyscallSet::Iterator SyscallSet::end() const {
+  return Iterator(set_, true);
+}
+
+bool SyscallSet::IsValid(uint32_t num) {
+  for (const SyscallRange& range : kValidSyscallRanges) {
+    if (num >= range.first && num <= range.last) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool operator==(const SyscallSet& lhs, const SyscallSet& rhs) {
+  return (lhs.set_ == rhs.set_);
+}
+
+SyscallSet::Iterator::Iterator(Set set, bool done)
+    : set_(set), done_(done), num_(0) {
+  // If the set doesn't contain 0, we need to skip to the next element.
+  if (!done && set_ == (IsValid(num_) ? Set::INVALID_ONLY : Set::VALID_ONLY)) {
+    ++*this;
+  }
+}
+
+uint32_t SyscallSet::Iterator::operator*() const {
+  DCHECK(!done_);
+  return num_;
+}
+
+SyscallSet::Iterator& SyscallSet::Iterator::operator++() {
+  DCHECK(!done_);
+
+  num_ = NextSyscall();
+  if (num_ == 0) {
+    done_ = true;
+  }
+
+  return *this;
+}
+
+// NextSyscall returns the next system call in the iterated system
+// call set after |num_|, or 0 if no such system call exists.
+uint32_t SyscallSet::Iterator::NextSyscall() const {
+  const bool want_valid = (set_ != Set::INVALID_ONLY);
+  const bool want_invalid = (set_ != Set::VALID_ONLY);
+
+  for (const SyscallRange& range : kValidSyscallRanges) {
+    if (want_invalid && range.first > 0 && num_ < range.first - 1) {
+      // Even when iterating invalid syscalls, we only include the end points;
+      // so skip directly to just before the next (valid) range.
+      return range.first - 1;
+    }
+    if (want_valid && num_ < range.first) {
+      return range.first;
+    }
+    if (want_valid && num_ < range.last) {
+      return num_ + 1;
+    }
+    if (want_invalid && num_ <= range.last) {
+      return range.last + 1;
+    }
+  }
+
+  if (want_invalid) {
+    // BPF programs only ever operate on unsigned quantities. So,
+    // that's how we iterate; we return values from
+    // 0..0xFFFFFFFFu. But there are places, where the kernel might
+    // interpret system call numbers as signed quantities, so the
+    // boundaries between signed and unsigned values are potential
+    // problem cases. We want to explicitly return these values from
+    // our iterator.
+    if (num_ < 0x7FFFFFFFu)
+      return 0x7FFFFFFFu;
+    if (num_ < 0x80000000u)
+      return 0x80000000u;
+
+    if (num_ < 0xFFFFFFFFu)
+      return 0xFFFFFFFFu;
+  }
+
+  return 0;
+}
+
+bool operator==(const SyscallSet::Iterator& lhs,
+                const SyscallSet::Iterator& rhs) {
+  DCHECK(lhs.set_ == rhs.set_);
+  return (lhs.done_ == rhs.done_) && (lhs.num_ == rhs.num_);
+}
+
+bool operator!=(const SyscallSet::Iterator& lhs,
+                const SyscallSet::Iterator& rhs) {
+  return !(lhs == rhs);
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/syscall_set.h b/libchrome/sandbox/linux/bpf_dsl/syscall_set.h
new file mode 100644
index 0000000..b9f076d
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/syscall_set.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
+#define SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
+
+#include <stdint.h>
+
+#include <iterator>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Iterates over the entire system call range from 0..0xFFFFFFFFu. This
+// iterator is aware of how system calls look like and will skip quickly
+// over ranges that can't contain system calls. It iterates more slowly
+// whenever it reaches a range that is potentially problematic, returning
+// the last invalid value before a valid range of system calls, and the
+// first invalid value after a valid range of syscalls. It iterates over
+// individual values whenever it is in the normal range for system calls
+// (typically MIN_SYSCALL..MAX_SYSCALL).
+//
+// Example usage:
+//   for (uint32_t sysnum : SyscallSet::All()) {
+//     // Do something with sysnum.
+//   }
+class SANDBOX_EXPORT SyscallSet {
+ public:
+  class Iterator;
+
+  SyscallSet(const SyscallSet& ss) : set_(ss.set_) {}
+  ~SyscallSet() {}
+
+  Iterator begin() const;
+  Iterator end() const;
+
+  // All returns a SyscallSet that contains both valid and invalid
+  // system call numbers.
+  static SyscallSet All() { return SyscallSet(Set::ALL); }
+
+  // ValidOnly returns a SyscallSet that contains only valid system
+  // call numbers.
+  static SyscallSet ValidOnly() { return SyscallSet(Set::VALID_ONLY); }
+
+  // InvalidOnly returns a SyscallSet that contains only invalid
+  // system call numbers, but still omits numbers in the middle of a
+  // range of invalid system call numbers.
+  static SyscallSet InvalidOnly() { return SyscallSet(Set::INVALID_ONLY); }
+
+  // IsValid returns whether |num| specifies a valid system call
+  // number.
+  static bool IsValid(uint32_t num);
+
+ private:
+  enum class Set { ALL, VALID_ONLY, INVALID_ONLY };
+
+  explicit SyscallSet(Set set) : set_(set) {}
+
+  Set set_;
+
+  friend bool operator==(const SyscallSet&, const SyscallSet&);
+  DISALLOW_ASSIGN(SyscallSet);
+};
+
+SANDBOX_EXPORT bool operator==(const SyscallSet& lhs, const SyscallSet& rhs);
+
+// Iterator provides C++ input iterator semantics for traversing a
+// SyscallSet.
+class SyscallSet::Iterator
+    : public std::iterator<std::input_iterator_tag, uint32_t> {
+ public:
+  Iterator(const Iterator& it)
+      : set_(it.set_), done_(it.done_), num_(it.num_) {}
+  ~Iterator() {}
+
+  uint32_t operator*() const;
+  Iterator& operator++();
+
+ private:
+  Iterator(Set set, bool done);
+
+  uint32_t NextSyscall() const;
+
+  Set set_;
+  bool done_;
+  uint32_t num_;
+
+  friend SyscallSet;
+  friend bool operator==(const Iterator&, const Iterator&);
+  DISALLOW_ASSIGN(Iterator);
+};
+
+SANDBOX_EXPORT bool operator==(const SyscallSet::Iterator& lhs,
+                               const SyscallSet::Iterator& rhs);
+SANDBOX_EXPORT bool operator!=(const SyscallSet::Iterator& lhs,
+                               const SyscallSet::Iterator& rhs);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
diff --git a/libchrome/sandbox/linux/bpf_dsl/syscall_set_unittest.cc b/libchrome/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
new file mode 100644
index 0000000..5069e8e
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/syscall_set_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+namespace {
+
+const SyscallSet kSyscallSets[] = {
+    SyscallSet::All(),
+    SyscallSet::InvalidOnly(),
+};
+
+SANDBOX_TEST(SyscallSet, Monotonous) {
+  for (const SyscallSet& set : kSyscallSets) {
+    uint32_t prev = 0;
+    bool have_prev = false;
+    for (uint32_t sysnum : set) {
+      if (have_prev) {
+        SANDBOX_ASSERT(sysnum > prev);
+      } else if (set == SyscallSet::All()) {
+        // The iterator should start at 0.
+        SANDBOX_ASSERT(sysnum == 0);
+      }
+
+      prev = sysnum;
+      have_prev = true;
+    }
+
+    // The iterator should always return 0xFFFFFFFFu as the last value.
+    SANDBOX_ASSERT(have_prev);
+    SANDBOX_ASSERT(prev == 0xFFFFFFFFu);
+  }
+}
+
+// AssertRange checks that SyscallIterator produces all system call
+// numbers in the inclusive range [min, max].
+void AssertRange(uint32_t min, uint32_t max) {
+  SANDBOX_ASSERT(min < max);
+  uint32_t prev = min - 1;
+  for (uint32_t sysnum : SyscallSet::All()) {
+    if (sysnum >= min && sysnum <= max) {
+      SANDBOX_ASSERT(prev == sysnum - 1);
+      prev = sysnum;
+    }
+  }
+  SANDBOX_ASSERT(prev == max);
+}
+
+SANDBOX_TEST(SyscallSet, ValidSyscallRanges) {
+  AssertRange(MIN_SYSCALL, MAX_PUBLIC_SYSCALL);
+#if defined(__arm__)
+  AssertRange(MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL);
+  AssertRange(MIN_GHOST_SYSCALL, MAX_SYSCALL);
+#endif
+}
+
+SANDBOX_TEST(SyscallSet, InvalidSyscalls) {
+  static const uint32_t kExpected[] = {
+#if defined(__mips__)
+    0,
+    MIN_SYSCALL - 1,
+#endif
+    MAX_PUBLIC_SYSCALL + 1,
+#if defined(__arm__)
+    MIN_PRIVATE_SYSCALL - 1,
+    MAX_PRIVATE_SYSCALL + 1,
+    MIN_GHOST_SYSCALL - 1,
+    MAX_SYSCALL + 1,
+#endif
+    0x7FFFFFFFu,
+    0x80000000u,
+    0xFFFFFFFFu,
+  };
+
+  for (const SyscallSet& set : kSyscallSets) {
+    size_t i = 0;
+    for (uint32_t sysnum : set) {
+      if (!SyscallSet::IsValid(sysnum)) {
+        SANDBOX_ASSERT(i < arraysize(kExpected));
+        SANDBOX_ASSERT(kExpected[i] == sysnum);
+        ++i;
+      }
+    }
+    SANDBOX_ASSERT(i == arraysize(kExpected));
+  }
+}
+
+SANDBOX_TEST(SyscallSet, ValidOnlyIsOnlyValid) {
+  for (uint32_t sysnum : SyscallSet::ValidOnly()) {
+    SANDBOX_ASSERT(SyscallSet::IsValid(sysnum));
+  }
+}
+
+SANDBOX_TEST(SyscallSet, InvalidOnlyIsOnlyInvalid) {
+  for (uint32_t sysnum : SyscallSet::InvalidOnly()) {
+    SANDBOX_ASSERT(!SyscallSet::IsValid(sysnum));
+  }
+}
+
+SANDBOX_TEST(SyscallSet, AllIsValidOnlyPlusInvalidOnly) {
+  std::vector<uint32_t> merged;
+  const SyscallSet valid_only = SyscallSet::ValidOnly();
+  const SyscallSet invalid_only = SyscallSet::InvalidOnly();
+  std::merge(valid_only.begin(),
+             valid_only.end(),
+             invalid_only.begin(),
+             invalid_only.end(),
+             std::back_inserter(merged));
+
+  const SyscallSet all = SyscallSet::All();
+  SANDBOX_ASSERT(merged == std::vector<uint32_t>(all.begin(), all.end()));
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/trap_registry.h b/libchrome/sandbox/linux/bpf_dsl/trap_registry.h
new file mode 100644
index 0000000..0a5d2f1
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/trap_registry.h
@@ -0,0 +1,73 @@
+// 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 SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
+#define SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This must match the kernel's seccomp_data structure.
+struct arch_seccomp_data {
+  int nr;
+  uint32_t arch;
+  uint64_t instruction_pointer;
+  uint64_t args[6];
+};
+
+namespace bpf_dsl {
+
+// TrapRegistry provides an interface for registering "trap handlers"
+// by associating them with non-zero 16-bit trap IDs. Trap IDs should
+// remain valid for the lifetime of the trap registry.
+class SANDBOX_EXPORT TrapRegistry {
+ public:
+  // TrapFnc is a pointer to a function that fulfills the trap handler
+  // function signature.
+  //
+  // Trap handlers follow the calling convention of native system
+  // calls; e.g., to report an error, they return an exit code in the
+  // range -1..-4096 instead of directly modifying errno. However,
+  // modifying errno is harmless, as the original value will be
+  // restored afterwards.
+  //
+  // Trap handlers are executed from signal context and possibly an
+  // async-signal context, so they must be async-signal safe:
+  // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
+  typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void* aux);
+
+  // Add registers the specified trap handler tuple and returns a
+  // non-zero trap ID that uniquely identifies the tuple for the life
+  // time of the trap registry. If the same tuple is registered
+  // multiple times, the same value will be returned each time.
+  virtual uint16_t Add(TrapFnc fnc, const void* aux, bool safe) = 0;
+
+  // EnableUnsafeTraps tries to enable unsafe traps and returns
+  // whether it was successful. This is a one-way operation.
+  //
+  // CAUTION: Enabling unsafe traps effectively defeats the security
+  // guarantees provided by the sandbox policy. TrapRegistry
+  // implementations should ensure unsafe traps are only enabled
+  // during testing.
+  virtual bool EnableUnsafeTraps() = 0;
+
+ protected:
+  TrapRegistry() {}
+
+  // TrapRegistry's destructor is intentionally non-virtual so that
+  // implementations can omit their destructor.  Instead we protect against
+  // misuse by marking it protected.
+  ~TrapRegistry() {}
+
+  DISALLOW_COPY_AND_ASSIGN(TrapRegistry);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
diff --git a/libchrome/sandbox/linux/bpf_dsl/verifier.cc b/libchrome/sandbox/linux/bpf_dsl/verifier.cc
new file mode 100644
index 0000000..b5383e5
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/verifier.cc
@@ -0,0 +1,225 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/verifier.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+struct State {
+  State(const std::vector<struct sock_filter>& p,
+        const struct arch_seccomp_data& d)
+      : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {}
+  const std::vector<struct sock_filter>& program;
+  const struct arch_seccomp_data& data;
+  unsigned int ip;
+  uint32_t accumulator;
+  bool acc_is_valid;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(State);
+};
+
+void Ld(State* state, const struct sock_filter& insn, const char** err) {
+  if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS ||
+      insn.jt != 0 || insn.jf != 0) {
+    *err = "Invalid BPF_LD instruction";
+    return;
+  }
+  if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
+    // We only allow loading of properly aligned 32bit quantities.
+    memcpy(&state->accumulator,
+           reinterpret_cast<const char*>(&state->data) + insn.k, 4);
+  } else {
+    *err = "Invalid operand in BPF_LD instruction";
+    return;
+  }
+  state->acc_is_valid = true;
+  return;
+}
+
+void Jmp(State* state, const struct sock_filter& insn, const char** err) {
+  if (BPF_OP(insn.code) == BPF_JA) {
+    if (state->ip + insn.k + 1 >= state->program.size() ||
+        state->ip + insn.k + 1 <= state->ip) {
+    compilation_failure:
+      *err = "Invalid BPF_JMP instruction";
+      return;
+    }
+    state->ip += insn.k;
+  } else {
+    if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid ||
+        state->ip + insn.jt + 1 >= state->program.size() ||
+        state->ip + insn.jf + 1 >= state->program.size()) {
+      goto compilation_failure;
+    }
+    switch (BPF_OP(insn.code)) {
+      case BPF_JEQ:
+        if (state->accumulator == insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      case BPF_JGT:
+        if (state->accumulator > insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      case BPF_JGE:
+        if (state->accumulator >= insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      case BPF_JSET:
+        if (state->accumulator & insn.k) {
+          state->ip += insn.jt;
+        } else {
+          state->ip += insn.jf;
+        }
+        break;
+      default:
+        goto compilation_failure;
+    }
+  }
+}
+
+uint32_t Ret(State*, const struct sock_filter& insn, const char** err) {
+  if (BPF_SRC(insn.code) != BPF_K) {
+    *err = "Invalid BPF_RET instruction";
+    return 0;
+  }
+  return insn.k;
+}
+
+void Alu(State* state, const struct sock_filter& insn, const char** err) {
+  if (BPF_OP(insn.code) == BPF_NEG) {
+    state->accumulator = -state->accumulator;
+    return;
+  } else {
+    if (BPF_SRC(insn.code) != BPF_K) {
+      *err = "Unexpected source operand in arithmetic operation";
+      return;
+    }
+    switch (BPF_OP(insn.code)) {
+      case BPF_ADD:
+        state->accumulator += insn.k;
+        break;
+      case BPF_SUB:
+        state->accumulator -= insn.k;
+        break;
+      case BPF_MUL:
+        state->accumulator *= insn.k;
+        break;
+      case BPF_DIV:
+        if (!insn.k) {
+          *err = "Illegal division by zero";
+          break;
+        }
+        state->accumulator /= insn.k;
+        break;
+      case BPF_MOD:
+        if (!insn.k) {
+          *err = "Illegal division by zero";
+          break;
+        }
+        state->accumulator %= insn.k;
+        break;
+      case BPF_OR:
+        state->accumulator |= insn.k;
+        break;
+      case BPF_XOR:
+        state->accumulator ^= insn.k;
+        break;
+      case BPF_AND:
+        state->accumulator &= insn.k;
+        break;
+      case BPF_LSH:
+        if (insn.k > 32) {
+          *err = "Illegal shift operation";
+          break;
+        }
+        state->accumulator <<= insn.k;
+        break;
+      case BPF_RSH:
+        if (insn.k > 32) {
+          *err = "Illegal shift operation";
+          break;
+        }
+        state->accumulator >>= insn.k;
+        break;
+      default:
+        *err = "Invalid operator in arithmetic operation";
+        break;
+    }
+  }
+}
+
+}  // namespace
+
+uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program,
+                               const struct arch_seccomp_data& data,
+                               const char** err) {
+  *err = NULL;
+  if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) {
+    *err = "Invalid program length";
+    return 0;
+  }
+  for (State state(program, data); !*err; ++state.ip) {
+    if (state.ip >= program.size()) {
+      *err = "Invalid instruction pointer in BPF program";
+      break;
+    }
+    const struct sock_filter& insn = program[state.ip];
+    switch (BPF_CLASS(insn.code)) {
+      case BPF_LD:
+        Ld(&state, insn, err);
+        break;
+      case BPF_JMP:
+        Jmp(&state, insn, err);
+        break;
+      case BPF_RET: {
+        uint32_t r = Ret(&state, insn, err);
+        switch (r & SECCOMP_RET_ACTION) {
+          case SECCOMP_RET_ALLOW:
+          case SECCOMP_RET_ERRNO:
+          case SECCOMP_RET_KILL:
+          case SECCOMP_RET_TRACE:
+          case SECCOMP_RET_TRAP:
+            break;
+          case SECCOMP_RET_INVALID:  // Should never show up in BPF program
+          default:
+            *err = "Unexpected return code found in BPF program";
+            return 0;
+        }
+        return r;
+      }
+      case BPF_ALU:
+        Alu(&state, insn, err);
+        break;
+      default:
+        *err = "Unexpected instruction in BPF program";
+        break;
+    }
+  }
+  return 0;
+}
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/bpf_dsl/verifier.h b/libchrome/sandbox/linux/bpf_dsl/verifier.h
new file mode 100644
index 0000000..9b25ab1
--- /dev/null
+++ b/libchrome/sandbox/linux/bpf_dsl/verifier.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 SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
+#define SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+struct sock_filter;
+
+namespace sandbox {
+struct arch_seccomp_data;
+
+namespace bpf_dsl {
+
+// TODO(mdempsky): This class doesn't perform any verification any more, so it
+// deserves a new name.
+class SANDBOX_EXPORT Verifier {
+ public:
+  // Evaluate a given BPF program for a particular set of system call
+  // parameters. If evaluation failed for any reason, "err" will be set to
+  // a non-NULL error string. Otherwise, the BPF program's result will be
+  // returned by the function and "err" is NULL.
+  // We do not actually implement the full BPF state machine, but only the
+  // parts that can actually be generated by our BPF compiler. If this code
+  // is used for purposes other than verifying the output of the sandbox's
+  // BPF compiler, we might have to extend this BPF interpreter.
+  static uint32_t EvaluateBPF(const std::vector<struct sock_filter>& program,
+                              const struct arch_seccomp_data& data,
+                              const char** err);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Verifier);
+};
+
+}  // namespace bpf_dsl
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_BPF_DSL_VERIFIER_H__
diff --git a/libchrome/sandbox/linux/integration_tests/DEPS b/libchrome/sandbox/linux/integration_tests/DEPS
new file mode 100644
index 0000000..d50729c
--- /dev/null
+++ b/libchrome/sandbox/linux/integration_tests/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+sandbox/linux/bpf_dsl",
+  "+sandbox/linux/seccomp-bpf",
+  "+sandbox/linux/services",
+  "+sandbox/linux/syscall_broker",
+  "+sandbox/linux/system_headers",
+]
diff --git a/libchrome/sandbox/linux/sandbox_linux.gypi b/libchrome/sandbox/linux/sandbox_linux.gypi
new file mode 100644
index 0000000..e96ae9e
--- /dev/null
+++ b/libchrome/sandbox/linux/sandbox_linux.gypi
@@ -0,0 +1,434 @@
+# Copyright (c) 2012 The Chromium 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': {
+    'conditions': [
+      ['OS=="linux"', {
+        'compile_suid_client': 1,
+        'compile_credentials': 1,
+        'use_base_test_suite': 1,
+      }, {
+        'compile_suid_client': 0,
+        'compile_credentials': 0,
+        'use_base_test_suite': 0,
+      }],
+      ['OS=="linux" and (target_arch=="ia32" or target_arch=="x64" or '
+         'target_arch=="mipsel")', {
+        'compile_seccomp_bpf_demo': 1,
+      }, {
+        'compile_seccomp_bpf_demo': 0,
+      }],
+    ],
+  },
+  'target_defaults': {
+    'target_conditions': [
+      # All linux/ files will automatically be excluded on Android
+      # so make sure we re-include them explicitly.
+      ['OS == "android"', {
+        'sources/': [
+          ['include', '^linux/'],
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    # We have two principal targets: sandbox and sandbox_linux_unittests
+    # All other targets are listed as dependencies.
+    # There is one notable exception: for historical reasons, chrome_sandbox is
+    # the setuid sandbox and is its own target.
+    {
+      'target_name': 'sandbox',
+      'type': 'none',
+      'dependencies': [
+        'sandbox_services',
+      ],
+      'conditions': [
+        [ 'compile_suid_client==1', {
+          'dependencies': [
+            'suid_sandbox_client',
+          ],
+        }],
+        # Compile seccomp BPF when we support it.
+        [ 'use_seccomp_bpf==1', {
+          'dependencies': [
+            'seccomp_bpf',
+            'seccomp_bpf_helpers',
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'sandbox_linux_test_utils',
+      'type': 'static_library',
+      'dependencies': [
+        '../testing/gtest.gyp:gtest',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [
+        'tests/sandbox_test_runner.cc',
+        'tests/sandbox_test_runner.h',
+        'tests/sandbox_test_runner_function_pointer.cc',
+        'tests/sandbox_test_runner_function_pointer.h',
+        'tests/test_utils.cc',
+        'tests/test_utils.h',
+        'tests/unit_tests.cc',
+        'tests/unit_tests.h',
+      ],
+      'conditions': [
+        [ 'use_seccomp_bpf==1', {
+          'sources': [
+            'seccomp-bpf/bpf_tester_compatibility_delegate.h',
+            'seccomp-bpf/bpf_tests.h',
+            'seccomp-bpf/sandbox_bpf_test_runner.cc',
+            'seccomp-bpf/sandbox_bpf_test_runner.h',
+          ],
+          'dependencies': [
+            'seccomp_bpf',
+          ]
+        }],
+        [ 'use_base_test_suite==1', {
+          'dependencies': [
+            '../base/base.gyp:test_support_base',
+          ],
+          'defines': [
+            'SANDBOX_USES_BASE_TEST_SUITE',
+          ],
+        }],
+      ],
+    },
+    {
+      # The main sandboxing test target.
+      'target_name': 'sandbox_linux_unittests',
+      'includes': [
+        'sandbox_linux_test_sources.gypi',
+      ],
+      'type': 'executable',
+      'conditions': [
+        [ 'OS == "android"', {
+          'variables': {
+            'test_type': 'gtest',
+            'test_suite_name': '<(_target_name)',
+          },
+          'includes': [
+            '../../build/android/test_runner.gypi',
+          ],
+        }]
+      ]
+    },
+    {
+      'target_name': 'seccomp_bpf',
+      'type': '<(component)',
+      'sources': [
+        'bpf_dsl/bpf_dsl.cc',
+        'bpf_dsl/bpf_dsl.h',
+        'bpf_dsl/bpf_dsl_forward.h',
+        'bpf_dsl/bpf_dsl_impl.h',
+        'bpf_dsl/codegen.cc',
+        'bpf_dsl/codegen.h',
+        'bpf_dsl/cons.h',
+        'bpf_dsl/errorcode.h',
+        'bpf_dsl/linux_syscall_ranges.h',
+        'bpf_dsl/policy.cc',
+        'bpf_dsl/policy.h',
+        'bpf_dsl/policy_compiler.cc',
+        'bpf_dsl/policy_compiler.h',
+        'bpf_dsl/seccomp_macros.h',
+        'bpf_dsl/seccomp_macros.h',
+        'bpf_dsl/syscall_set.cc',
+        'bpf_dsl/syscall_set.h',
+        'bpf_dsl/trap_registry.h',
+        'seccomp-bpf/die.cc',
+        'seccomp-bpf/die.h',
+        'seccomp-bpf/sandbox_bpf.cc',
+        'seccomp-bpf/sandbox_bpf.h',
+        'seccomp-bpf/syscall.cc',
+        'seccomp-bpf/syscall.h',
+        'seccomp-bpf/trap.cc',
+        'seccomp-bpf/trap.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        'sandbox_services',
+        'sandbox_services_headers',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'includes': [
+        # Disable LTO due to compiler bug
+        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57703
+        '../../build/android/disable_gcc_lto.gypi',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+    {
+      'target_name': 'seccomp_bpf_helpers',
+      'type': '<(component)',
+      'sources': [
+        'seccomp-bpf-helpers/baseline_policy.cc',
+        'seccomp-bpf-helpers/baseline_policy.h',
+        'seccomp-bpf-helpers/sigsys_handlers.cc',
+        'seccomp-bpf-helpers/sigsys_handlers.h',
+        'seccomp-bpf-helpers/syscall_parameters_restrictions.cc',
+        'seccomp-bpf-helpers/syscall_parameters_restrictions.h',
+        'seccomp-bpf-helpers/syscall_sets.cc',
+        'seccomp-bpf-helpers/syscall_sets.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        'sandbox_services',
+        'seccomp_bpf',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+    {
+      # The setuid sandbox, for Linux
+      'target_name': 'chrome_sandbox',
+      'type': 'executable',
+      'sources': [
+        'suid/common/sandbox.h',
+        'suid/common/suid_unsafe_environment_variables.h',
+        'suid/process_util.h',
+        'suid/process_util_linux.c',
+        'suid/sandbox.c',
+      ],
+      'cflags': [
+        # For ULLONG_MAX
+        '-std=gnu99',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      # Do not use any sanitizer tools with this binary. http://crbug.com/382766
+      'cflags/': [
+        ['exclude', '-fsanitize'],
+      ],
+      'ldflags/': [
+        ['exclude', '-fsanitize'],
+      ],
+    },
+    { 'target_name': 'sandbox_services',
+      'type': '<(component)',
+      'sources': [
+        'services/init_process_reaper.cc',
+        'services/init_process_reaper.h',
+        'services/proc_util.cc',
+        'services/proc_util.h',
+        'services/resource_limits.cc',
+        'services/resource_limits.h',
+        'services/scoped_process.cc',
+        'services/scoped_process.h',
+        'services/syscall_wrappers.cc',
+        'services/syscall_wrappers.h',
+        'services/thread_helpers.cc',
+        'services/thread_helpers.h',
+        'services/yama.cc',
+        'services/yama.h',
+        'syscall_broker/broker_channel.cc',
+        'syscall_broker/broker_channel.h',
+        'syscall_broker/broker_client.cc',
+        'syscall_broker/broker_client.h',
+        'syscall_broker/broker_common.h',
+        'syscall_broker/broker_file_permission.cc',
+        'syscall_broker/broker_file_permission.h',
+        'syscall_broker/broker_host.cc',
+        'syscall_broker/broker_host.h',
+        'syscall_broker/broker_policy.cc',
+        'syscall_broker/broker_policy.h',
+        'syscall_broker/broker_process.cc',
+        'syscall_broker/broker_process.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'conditions': [
+        ['compile_credentials==1', {
+          'sources': [
+            'services/credentials.cc',
+            'services/credentials.h',
+            'services/namespace_sandbox.cc',
+            'services/namespace_sandbox.h',
+            'services/namespace_utils.cc',
+            'services/namespace_utils.h',
+          ],
+          'dependencies': [
+            # for capability.h.
+            'sandbox_services_headers',
+          ],
+        }],
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    { 'target_name': 'sandbox_services_headers',
+      'type': 'none',
+      'sources': [
+        'system_headers/arm64_linux_syscalls.h',
+        'system_headers/arm64_linux_ucontext.h',
+        'system_headers/arm_linux_syscalls.h',
+        'system_headers/arm_linux_ucontext.h',
+        'system_headers/capability.h',
+        'system_headers/i386_linux_ucontext.h',
+        'system_headers/linux_futex.h',
+        'system_headers/linux_seccomp.h',
+        'system_headers/linux_syscalls.h',
+        'system_headers/linux_time.h',
+        'system_headers/linux_ucontext.h',
+        'system_headers/mips_linux_syscalls.h',
+        'system_headers/mips_linux_ucontext.h',
+        'system_headers/x86_32_linux_syscalls.h',
+        'system_headers/x86_64_linux_syscalls.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
+      'target_name': 'suid_sandbox_client',
+      'type': '<(component)',
+      'sources': [
+        'suid/common/sandbox.h',
+        'suid/common/suid_unsafe_environment_variables.h',
+        'suid/client/setuid_sandbox_client.cc',
+        'suid/client/setuid_sandbox_client.h',
+        'suid/client/setuid_sandbox_host.cc',
+        'suid/client/setuid_sandbox_host.h',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        'sandbox_services',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
+      'target_name': 'bpf_dsl_golden',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'generate',
+          'inputs': [
+            'bpf_dsl/golden/generate.py',
+            'bpf_dsl/golden/i386/ArgSizePolicy.txt',
+            'bpf_dsl/golden/i386/BasicPolicy.txt',
+            'bpf_dsl/golden/i386/ElseIfPolicy.txt',
+            'bpf_dsl/golden/i386/MaskingPolicy.txt',
+            'bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt',
+            'bpf_dsl/golden/i386/NegativeConstantsPolicy.txt',
+            'bpf_dsl/golden/i386/SwitchPolicy.txt',
+            'bpf_dsl/golden/x86-64/ArgSizePolicy.txt',
+            'bpf_dsl/golden/x86-64/BasicPolicy.txt',
+            'bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt',
+            'bpf_dsl/golden/x86-64/ElseIfPolicy.txt',
+            'bpf_dsl/golden/x86-64/MaskingPolicy.txt',
+            'bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt',
+            'bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt',
+            'bpf_dsl/golden/x86-64/SwitchPolicy.txt',
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/sandbox/linux/bpf_dsl/golden/golden_files.h',
+          ],
+          'action': [
+            'python',
+            'linux/bpf_dsl/golden/generate.py',
+            '<(SHARED_INTERMEDIATE_DIR)/sandbox/linux/bpf_dsl/golden/golden_files.h',
+            'linux/bpf_dsl/golden/i386/ArgSizePolicy.txt',
+            'linux/bpf_dsl/golden/i386/BasicPolicy.txt',
+            'linux/bpf_dsl/golden/i386/ElseIfPolicy.txt',
+            'linux/bpf_dsl/golden/i386/MaskingPolicy.txt',
+            'linux/bpf_dsl/golden/i386/MoreBooleanLogicPolicy.txt',
+            'linux/bpf_dsl/golden/i386/NegativeConstantsPolicy.txt',
+            'linux/bpf_dsl/golden/i386/SwitchPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/ArgSizePolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/BasicPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/BooleanLogicPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/ElseIfPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/MaskingPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/MoreBooleanLogicPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/NegativeConstantsPolicy.txt',
+            'linux/bpf_dsl/golden/x86-64/SwitchPolicy.txt',
+          ],
+          'message': 'Generating header from golden files ...',
+        },
+      ],
+    },
+  ],
+  'conditions': [
+    [ 'OS=="android"', {
+      'targets': [
+      {
+        'target_name': 'sandbox_linux_unittests_deps',
+        'type': 'none',
+        'dependencies': [
+          'sandbox_linux_unittests',
+        ],
+        'variables': {
+           'output_dir': '<(PRODUCT_DIR)/sandbox_linux_unittests__dist/',
+           'native_binary': '<(PRODUCT_DIR)/sandbox_linux_unittests',
+           'include_main_binary': 1,
+        },
+        'includes': [
+          '../../build/android/native_app_dependencies.gypi'
+        ],
+      }],
+    }],
+    [ 'OS=="android"', {
+      'conditions': [
+        ['test_isolation_mode != "noop"', {
+          'targets': [
+            {
+              'target_name': 'sandbox_linux_unittests_android_run',
+              'type': 'none',
+              'dependencies': [
+                'sandbox_linux_unittests',
+              ],
+              'includes': [
+                '../../build/isolate.gypi',
+              ],
+              'sources': [
+                '../sandbox_linux_unittests_android.isolate',
+              ],
+            },
+          ],
+        },
+      ],
+    ],
+    }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'sandbox_linux_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'sandbox_linux_unittests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sandbox_linux_unittests.isolate',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp b/libchrome/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp
new file mode 100644
index 0000000..50e637c
--- /dev/null
+++ b/libchrome/sandbox/linux/sandbox_linux_nacl_nonsfi.gyp
@@ -0,0 +1,87 @@
+# 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': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../../build/common_untrusted.gypi',
+  ],
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'sandbox_linux_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libsandbox_linux_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+            'compile_flags': [
+              '-fgnu-inline-asm',
+            ],
+            'sources': [
+              # This is the subset of linux build target, needed for
+              # nacl_helper_nonsfi's sandbox implementation.
+              'bpf_dsl/bpf_dsl.cc',
+              'bpf_dsl/codegen.cc',
+              'bpf_dsl/policy.cc',
+              'bpf_dsl/policy_compiler.cc',
+              'bpf_dsl/syscall_set.cc',
+              'seccomp-bpf-helpers/sigsys_handlers.cc',
+              'seccomp-bpf-helpers/syscall_parameters_restrictions.cc',
+              'seccomp-bpf/die.cc',
+              'seccomp-bpf/sandbox_bpf.cc',
+              'seccomp-bpf/syscall.cc',
+              'seccomp-bpf/trap.cc',
+              'services/credentials.cc',
+              'services/namespace_sandbox.cc',
+              'services/namespace_utils.cc',
+              'services/proc_util.cc',
+              'services/resource_limits.cc',
+              'services/syscall_wrappers.cc',
+              'services/thread_helpers.cc',
+              'suid/client/setuid_sandbox_client.cc',
+            ],
+          },
+          'dependencies': [
+            '../../base/base_nacl.gyp:base_nacl_nonsfi',
+          ],
+        },
+      ],
+    }],
+
+    ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
+      'targets': [
+        {
+          'target_name': 'sandbox_linux_test_utils_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libsandbox_linux_test_utils_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              'seccomp-bpf/sandbox_bpf_test_runner.cc',
+              'tests/sandbox_test_runner.cc',
+              'tests/unit_tests.cc',
+            ],
+          },
+          'dependencies': [
+            '../../testing/gtest_nacl.gyp:gtest_nacl',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/sandbox/linux/sandbox_linux_test_sources.gypi b/libchrome/sandbox/linux/sandbox_linux_test_sources.gypi
new file mode 100644
index 0000000..612814e
--- /dev/null
+++ b/libchrome/sandbox/linux/sandbox_linux_test_sources.gypi
@@ -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.
+
+# Tests need to be compiled in the same link unit, so we have to list them
+# in a separate .gypi file.
+{
+  'dependencies': [
+    'sandbox',
+    'sandbox_linux_test_utils',
+    'sandbox_services',
+    '../base/base.gyp:base',
+    '../testing/gtest.gyp:gtest',
+  ],
+  'include_dirs': [
+    '../..',
+  ],
+  'sources': [
+    'services/proc_util_unittest.cc',
+    'services/scoped_process_unittest.cc',
+    'services/resource_limits_unittests.cc',
+    'services/syscall_wrappers_unittest.cc',
+    'services/thread_helpers_unittests.cc',
+    'services/yama_unittests.cc',
+    'syscall_broker/broker_file_permission_unittest.cc',
+    'syscall_broker/broker_process_unittest.cc',
+    'tests/main.cc',
+    'tests/scoped_temporary_file.cc',
+    'tests/scoped_temporary_file.h',
+    'tests/scoped_temporary_file_unittest.cc',
+    'tests/test_utils_unittest.cc',
+    'tests/unit_tests_unittest.cc',
+  ],
+  'conditions': [
+    [ 'compile_suid_client==1', {
+      'sources': [
+        'suid/client/setuid_sandbox_client_unittest.cc',
+        'suid/client/setuid_sandbox_host_unittest.cc',
+      ],
+    }],
+    [ 'use_seccomp_bpf==1', {
+      'sources': [
+        'bpf_dsl/bpf_dsl_unittest.cc',
+        'bpf_dsl/codegen_unittest.cc',
+        'bpf_dsl/cons_unittest.cc',
+        'bpf_dsl/dump_bpf.cc',
+        'bpf_dsl/dump_bpf.h',
+        'bpf_dsl/syscall_set_unittest.cc',
+        'bpf_dsl/test_trap_registry.cc',
+        'bpf_dsl/test_trap_registry.h',
+        'bpf_dsl/test_trap_registry_unittest.cc',
+        'bpf_dsl/verifier.cc',
+        'bpf_dsl/verifier.h',
+        'integration_tests/bpf_dsl_seccomp_unittest.cc',
+        'integration_tests/seccomp_broker_process_unittest.cc',
+        'seccomp-bpf-helpers/baseline_policy_unittest.cc',
+        'seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc',
+        'seccomp-bpf/bpf_tests_unittest.cc',
+        'seccomp-bpf/sandbox_bpf_unittest.cc',
+        'seccomp-bpf/syscall_unittest.cc',
+        'seccomp-bpf/trap_unittest.cc',
+      ],
+      'dependencies': [
+        'bpf_dsl_golden',
+      ],
+    }],
+    [ 'compile_credentials==1', {
+      'sources': [
+        'integration_tests/namespace_unix_domain_socket_unittest.cc',
+        'services/credentials_unittest.cc',
+        'services/namespace_utils_unittest.cc',
+      ],
+      'dependencies': [
+        '../build/linux/system.gyp:libcap'
+      ],
+      'conditions': [
+        [ 'use_base_test_suite==1', {
+          'sources': [
+            'services/namespace_sandbox_unittest.cc',
+          ]
+        }]
+      ],
+    }],
+    [ 'use_base_test_suite==1', {
+      'dependencies': [
+        '../base/base.gyp:test_support_base',
+      ],
+      'defines': [
+        'SANDBOX_USES_BASE_TEST_SUITE',
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/DEPS b/libchrome/sandbox/linux/seccomp-bpf-helpers/DEPS
new file mode 100644
index 0000000..4419fd1
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+  "+sandbox/linux/bpf_dsl",
+  "+sandbox/linux/seccomp-bpf",
+  "+sandbox/linux/services",
+  "+sandbox/linux/system_headers",
+  "+third_party/lss/linux_syscall_support.h",
+]
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
new file mode 100644
index 0000000..2bf572c
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc
@@ -0,0 +1,284 @@
+// 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 "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
+#include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+#if !defined(SO_PEEK_OFF)
+#define SO_PEEK_OFF 42
+#endif
+
+// Changing this implementation will have an effect on *all* policies.
+// Currently this means: Renderer/Worker, GPU, Flash and NaCl.
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Arg;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::If;
+using sandbox::bpf_dsl::ResultExpr;
+
+namespace sandbox {
+
+namespace {
+
+bool IsBaselinePolicyAllowed(int sysno) {
+  return SyscallSets::IsAllowedAddressSpaceAccess(sysno) ||
+         SyscallSets::IsAllowedBasicScheduler(sysno) ||
+         SyscallSets::IsAllowedEpoll(sysno) ||
+         SyscallSets::IsAllowedFileSystemAccessViaFd(sysno) ||
+         SyscallSets::IsAllowedFutex(sysno) ||
+         SyscallSets::IsAllowedGeneralIo(sysno) ||
+         SyscallSets::IsAllowedGetOrModifySocket(sysno) ||
+         SyscallSets::IsAllowedGettime(sysno) ||
+         SyscallSets::IsAllowedProcessStartOrDeath(sysno) ||
+         SyscallSets::IsAllowedSignalHandling(sysno) ||
+         SyscallSets::IsGetSimpleId(sysno) ||
+         SyscallSets::IsKernelInternalApi(sysno) ||
+#if defined(__arm__)
+         SyscallSets::IsArmPrivate(sysno) ||
+#endif
+#if defined(__mips__)
+         SyscallSets::IsMipsPrivate(sysno) ||
+#endif
+         SyscallSets::IsAllowedOperationOnFd(sysno);
+}
+
+// System calls that will trigger the crashing SIGSYS handler.
+bool IsBaselinePolicyWatched(int sysno) {
+  return SyscallSets::IsAdminOperation(sysno) ||
+         SyscallSets::IsAdvancedScheduler(sysno) ||
+         SyscallSets::IsAdvancedTimer(sysno) ||
+         SyscallSets::IsAsyncIo(sysno) ||
+         SyscallSets::IsDebug(sysno) ||
+         SyscallSets::IsEventFd(sysno) ||
+         SyscallSets::IsExtendedAttributes(sysno) ||
+         SyscallSets::IsFaNotify(sysno) ||
+         SyscallSets::IsFsControl(sysno) ||
+         SyscallSets::IsGlobalFSViewChange(sysno) ||
+         SyscallSets::IsGlobalProcessEnvironment(sysno) ||
+         SyscallSets::IsGlobalSystemStatus(sysno) ||
+         SyscallSets::IsInotify(sysno) ||
+         SyscallSets::IsKernelModule(sysno) ||
+         SyscallSets::IsKeyManagement(sysno) ||
+         SyscallSets::IsKill(sysno) ||
+         SyscallSets::IsMessageQueue(sysno) ||
+         SyscallSets::IsMisc(sysno) ||
+#if defined(__x86_64__)
+         SyscallSets::IsNetworkSocketInformation(sysno) ||
+#endif
+         SyscallSets::IsNuma(sysno) ||
+         SyscallSets::IsPrctl(sysno) ||
+         SyscallSets::IsProcessGroupOrSession(sysno) ||
+#if defined(__i386__) || defined(__mips__)
+         SyscallSets::IsSocketCall(sysno) ||
+#endif
+#if defined(__arm__)
+         SyscallSets::IsArmPciConfig(sysno) ||
+#endif
+#if defined(__mips__)
+         SyscallSets::IsMipsMisc(sysno) ||
+#endif
+         SyscallSets::IsTimer(sysno);
+}
+
+// |fs_denied_errno| is the errno return for denied filesystem access.
+ResultExpr EvaluateSyscallImpl(int fs_denied_errno,
+                               pid_t current_pid,
+                               int sysno) {
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
+    defined(MEMORY_SANITIZER)
+  // TCGETS is required by the sanitizers on failure.
+  if (sysno == __NR_ioctl) {
+    return RestrictIoctl();
+  }
+
+  if (sysno == __NR_sched_getaffinity) {
+    return Allow();
+  }
+
+  // Used when RSS limiting is enabled in sanitizers.
+  if (sysno == __NR_getrusage) {
+    return RestrictGetrusage();
+  }
+
+  if (sysno == __NR_sigaltstack) {
+    // Required for better stack overflow detection in ASan. Disallowed in
+    // non-ASan builds.
+    return Allow();
+  }
+#endif  // defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||
+        // defined(MEMORY_SANITIZER)
+
+  if (IsBaselinePolicyAllowed(sysno)) {
+    return Allow();
+  }
+
+#if defined(OS_ANDROID)
+  // Needed for thread creation.
+  if (sysno == __NR_sigaltstack)
+    return Allow();
+#endif
+
+  if (sysno == __NR_clock_gettime) {
+    return RestrictClockID();
+  }
+
+  if (sysno == __NR_clone) {
+    return RestrictCloneToThreadsAndEPERMFork();
+  }
+
+  if (sysno == __NR_fcntl)
+    return RestrictFcntlCommands();
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+  if (sysno == __NR_fcntl64)
+    return RestrictFcntlCommands();
+#endif
+
+#if !defined(__aarch64__)
+  // fork() is never used as a system call (clone() is used instead), but we
+  // have seen it in fallback code on Android.
+  if (sysno == __NR_fork) {
+    return Error(EPERM);
+  }
+#endif
+
+  if (sysno == __NR_futex)
+    return RestrictFutex();
+
+  if (sysno == __NR_set_robust_list)
+    return Error(EPERM);
+
+  if (sysno == __NR_getpriority || sysno ==__NR_setpriority)
+    return RestrictGetSetpriority(current_pid);
+
+  if (sysno == __NR_madvise) {
+    // Only allow MADV_DONTNEED (aka MADV_FREE).
+    const Arg<int> advice(2);
+    return If(advice == MADV_DONTNEED, Allow()).Else(Error(EPERM));
+  }
+
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+  if (sysno == __NR_mmap)
+    return RestrictMmapFlags();
+#endif
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+  if (sysno == __NR_mmap2)
+    return RestrictMmapFlags();
+#endif
+
+  if (sysno == __NR_mprotect)
+    return RestrictMprotectFlags();
+
+  if (sysno == __NR_prctl)
+    return RestrictPrctl();
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+  if (sysno == __NR_socketpair) {
+    // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
+    static_assert(AF_UNIX == PF_UNIX,
+                  "af_unix and pf_unix should not be different");
+    const Arg<int> domain(0);
+    return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS());
+  }
+#endif
+
+  if (SyscallSets::IsKill(sysno)) {
+    return RestrictKillTarget(current_pid, sysno);
+  }
+
+  if (SyscallSets::IsFileSystem(sysno) ||
+      SyscallSets::IsCurrentDirectory(sysno)) {
+    return Error(fs_denied_errno);
+  }
+
+  if (SyscallSets::IsSeccomp(sysno))
+    return Error(EPERM);
+
+  if (SyscallSets::IsAnySystemV(sysno)) {
+    return Error(EPERM);
+  }
+
+  if (SyscallSets::IsUmask(sysno) ||
+      SyscallSets::IsDeniedFileSystemAccessViaFd(sysno) ||
+      SyscallSets::IsDeniedGetOrModifySocket(sysno) ||
+      SyscallSets::IsProcessPrivilegeChange(sysno)) {
+    return Error(EPERM);
+  }
+
+#if defined(__i386__) || defined(__mips__)
+  if (SyscallSets::IsSocketCall(sysno))
+    return RestrictSocketcallCommand();
+#endif
+
+#if !defined(__i386__)
+  if (sysno == __NR_getsockopt || sysno ==__NR_setsockopt) {
+    // Used by Mojo EDK to catch a message pipe being sent over itself.
+    const Arg<int> level(1);
+    const Arg<int> optname(2);
+    return If(AllOf(level == SOL_SOCKET, optname == SO_PEEK_OFF), Allow())
+        .Else(CrashSIGSYS());
+  }
+#endif
+
+  if (IsBaselinePolicyWatched(sysno)) {
+    // Previously unseen syscalls. TODO(jln): some of these should
+    // be denied gracefully right away.
+    return CrashSIGSYS();
+  }
+
+  // In any other case crash the program with our SIGSYS handler.
+  return CrashSIGSYS();
+}
+
+}  // namespace.
+
+// Unfortunately C++03 doesn't allow delegated constructors.
+// Call other constructor when C++11 lands.
+BaselinePolicy::BaselinePolicy() : BaselinePolicy(EPERM) {}
+
+BaselinePolicy::BaselinePolicy(int fs_denied_errno)
+    : fs_denied_errno_(fs_denied_errno), policy_pid_(sys_getpid()) {
+}
+
+BaselinePolicy::~BaselinePolicy() {
+  // Make sure that this policy is created, used and destroyed by a single
+  // process.
+  DCHECK_EQ(sys_getpid(), policy_pid_);
+}
+
+ResultExpr BaselinePolicy::EvaluateSyscall(int sysno) const {
+  // Sanity check that we're only called with valid syscall numbers.
+  DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+  // Make sure that this policy is used in the creating process.
+  if (1 == sysno) {
+    DCHECK_EQ(sys_getpid(), policy_pid_);
+  }
+  return EvaluateSyscallImpl(fs_denied_errno_, policy_pid_, sysno);
+}
+
+ResultExpr BaselinePolicy::InvalidSyscall() const {
+  return CrashSIGSYS();
+}
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h b/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h
new file mode 100644
index 0000000..fa40e72
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy.h
@@ -0,0 +1,51 @@
+// 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 SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
+
+#include <sys/types.h>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This is a helper to build seccomp-bpf policies, i.e. policies for a sandbox
+// that reduces the Linux kernel's attack surface. Given its nature, it doesn't
+// have a clear semantics and is mostly "implementation-defined".
+//
+// This class implements the Policy interface with a "baseline"
+// policy for use within Chromium.
+// The "baseline" policy is somewhat arbitrary. All Chromium policies are an
+// alteration of it, and it represents a reasonable common ground to run most
+// code in a sandboxed environment.
+// A baseline policy is only valid for the process for which this object was
+// instantiated (so do not fork() and use it in a child).
+class SANDBOX_EXPORT BaselinePolicy : public bpf_dsl::Policy {
+ public:
+  BaselinePolicy();
+  // |fs_denied_errno| is the errno returned when a filesystem access system
+  // call is denied.
+  explicit BaselinePolicy(int fs_denied_errno);
+  ~BaselinePolicy() override;
+
+  bpf_dsl::ResultExpr EvaluateSyscall(int system_call_number) const override;
+  bpf_dsl::ResultExpr InvalidSyscall() const override;
+  pid_t policy_pid() const { return policy_pid_; }
+
+ private:
+  int fs_denied_errno_;
+
+  // The PID that the policy applies to (should be equal to the current pid).
+  pid_t policy_pid_;
+
+  DISALLOW_COPY_AND_ASSIGN(BaselinePolicy);
+};
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_BASELINE_POLICY_H_
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
new file mode 100644
index 0000000..f0392b1
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc
@@ -0,0 +1,399 @@
+// 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 "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sched.h>
+#include <signal.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/linux_futex.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+#if !defined(SO_PEEK_OFF)
+#define SO_PEEK_OFF 42
+#endif
+
+namespace sandbox {
+
+namespace {
+
+// This also tests that read(), write() and fstat() are allowed.
+void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) {
+  BPF_ASSERT_LE(0, read_end.get());
+  BPF_ASSERT_LE(0, write_end.get());
+  struct stat stat_buf;
+  int sys_ret = fstat(read_end.get(), &stat_buf);
+  BPF_ASSERT_EQ(0, sys_ret);
+  BPF_ASSERT(S_ISFIFO(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode));
+
+  const ssize_t kTestTransferSize = 4;
+  static const char kTestString[kTestTransferSize] = {'T', 'E', 'S', 'T'};
+  ssize_t transfered = 0;
+
+  transfered =
+      HANDLE_EINTR(write(write_end.get(), kTestString, kTestTransferSize));
+  BPF_ASSERT_EQ(kTestTransferSize, transfered);
+  char read_buf[kTestTransferSize + 1] = {0};
+  transfered = HANDLE_EINTR(read(read_end.get(), read_buf, sizeof(read_buf)));
+  BPF_ASSERT_EQ(kTestTransferSize, transfered);
+  BPF_ASSERT_EQ(0, memcmp(kTestString, read_buf, kTestTransferSize));
+}
+
+// Test that a few easy-to-test system calls are allowed.
+BPF_TEST_C(BaselinePolicy, BaselinePolicyBasicAllowed, BaselinePolicy) {
+  BPF_ASSERT_EQ(0, sched_yield());
+
+  int pipefd[2];
+  int sys_ret = pipe(pipefd);
+  BPF_ASSERT_EQ(0, sys_ret);
+  TestPipeOrSocketPair(base::ScopedFD(pipefd[0]), base::ScopedFD(pipefd[1]));
+
+  BPF_ASSERT_LE(1, getpid());
+  BPF_ASSERT_LE(0, getuid());
+}
+
+BPF_TEST_C(BaselinePolicy, FchmodErrno, BaselinePolicy) {
+  int ret = fchmod(-1, 07777);
+  BPF_ASSERT_EQ(-1, ret);
+  // Without the sandbox, this would EBADF instead.
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_TEST_C(BaselinePolicy, ForkErrno, BaselinePolicy) {
+  errno = 0;
+  pid_t pid = fork();
+  const int fork_errno = errno;
+  TestUtils::HandlePostForkReturn(pid);
+
+  BPF_ASSERT_EQ(-1, pid);
+  BPF_ASSERT_EQ(EPERM, fork_errno);
+}
+
+pid_t ForkX86Glibc() {
+  static pid_t ptid;
+  return sys_clone(CLONE_PARENT_SETTID | SIGCHLD, nullptr, &ptid, nullptr,
+                   nullptr);
+}
+
+BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) {
+  errno = 0;
+  pid_t pid = ForkX86Glibc();
+  const int fork_errno = errno;
+  TestUtils::HandlePostForkReturn(pid);
+
+  BPF_ASSERT_EQ(-1, pid);
+  BPF_ASSERT_EQ(EPERM, fork_errno);
+}
+
+pid_t ForkARMGlibc() {
+  static pid_t ctid;
+  return sys_clone(CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, nullptr,
+                   nullptr, &ctid, nullptr);
+}
+
+BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) {
+  errno = 0;
+  pid_t pid = ForkARMGlibc();
+  const int fork_errno = errno;
+  TestUtils::HandlePostForkReturn(pid);
+
+  BPF_ASSERT_EQ(-1, pid);
+  BPF_ASSERT_EQ(EPERM, fork_errno);
+}
+
+BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) {
+  base::Thread thread("sandbox_tests");
+  BPF_ASSERT(thread.Start());
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 DisallowedCloneFlagCrashes,
+                 DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  pid_t pid = sys_clone(CLONE_THREAD | SIGCHLD);
+  TestUtils::HandlePostForkReturn(pid);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 DisallowedKillCrashes,
+                 DEATH_SEGV_MESSAGE(GetKillErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  BPF_ASSERT_NE(1, getpid());
+  kill(1, 0);
+  _exit(0);
+}
+
+BPF_TEST_C(BaselinePolicy, CanKillSelf, BaselinePolicy) {
+  int sys_ret = kill(getpid(), 0);
+  BPF_ASSERT_EQ(0, sys_ret);
+}
+
+BPF_TEST_C(BaselinePolicy, Socketpair, BaselinePolicy) {
+  int sv[2];
+  int sys_ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv);
+  BPF_ASSERT_EQ(0, sys_ret);
+  TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1]));
+
+  sys_ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv);
+  BPF_ASSERT_EQ(0, sys_ret);
+  TestPipeOrSocketPair(base::ScopedFD(sv[0]), base::ScopedFD(sv[1]));
+}
+
+// Not all architectures can restrict the domain for socketpair().
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SocketpairWrongDomain,
+                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int sv[2];
+  ignore_result(socketpair(AF_INET, SOCK_STREAM, 0, sv));
+  _exit(1);
+}
+#endif  // defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+
+BPF_TEST_C(BaselinePolicy, EPERM_open, BaselinePolicy) {
+  errno = 0;
+  int sys_ret = open("/proc/cpuinfo", O_RDONLY);
+  BPF_ASSERT_EQ(-1, sys_ret);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_TEST_C(BaselinePolicy, EPERM_access, BaselinePolicy) {
+  errno = 0;
+  int sys_ret = access("/proc/cpuinfo", R_OK);
+  BPF_ASSERT_EQ(-1, sys_ret);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_TEST_C(BaselinePolicy, EPERM_getcwd, BaselinePolicy) {
+  errno = 0;
+  char buf[1024];
+  char* cwd = getcwd(buf, sizeof(buf));
+  BPF_ASSERT_EQ(NULL, cwd);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SIGSYS_InvalidSyscall,
+                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  Syscall::InvalidCall();
+}
+
+// A failing test using this macro could be problematic since we perform
+// system calls by passing "0" as every argument.
+// The kernel could SIGSEGV the process or the system call itself could reboot
+// the machine. Some thoughts have been given when hand-picking the system
+// calls below to limit any potential side effects outside of the current
+// process.
+#define TEST_BASELINE_SIGSYS(sysno)                                      \
+  BPF_DEATH_TEST_C(BaselinePolicy,                                       \
+                   SIGSYS_##sysno,                                       \
+                   DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()), \
+                   BaselinePolicy) {                                     \
+    syscall(sysno, 0, 0, 0, 0, 0, 0);                                    \
+    _exit(1);                                                            \
+  }
+
+TEST_BASELINE_SIGSYS(__NR_acct);
+TEST_BASELINE_SIGSYS(__NR_chroot);
+TEST_BASELINE_SIGSYS(__NR_fanotify_init);
+TEST_BASELINE_SIGSYS(__NR_fgetxattr);
+TEST_BASELINE_SIGSYS(__NR_getcpu);
+TEST_BASELINE_SIGSYS(__NR_getitimer);
+TEST_BASELINE_SIGSYS(__NR_init_module);
+TEST_BASELINE_SIGSYS(__NR_io_cancel);
+TEST_BASELINE_SIGSYS(__NR_keyctl);
+TEST_BASELINE_SIGSYS(__NR_mq_open);
+TEST_BASELINE_SIGSYS(__NR_ptrace);
+TEST_BASELINE_SIGSYS(__NR_sched_setaffinity);
+TEST_BASELINE_SIGSYS(__NR_setpgid);
+TEST_BASELINE_SIGSYS(__NR_swapon);
+TEST_BASELINE_SIGSYS(__NR_sysinfo);
+TEST_BASELINE_SIGSYS(__NR_syslog);
+TEST_BASELINE_SIGSYS(__NR_timer_create);
+
+#if !defined(__aarch64__)
+TEST_BASELINE_SIGSYS(__NR_eventfd);
+TEST_BASELINE_SIGSYS(__NR_inotify_init);
+TEST_BASELINE_SIGSYS(__NR_vserver);
+#endif
+
+#if defined(LIBC_GLIBC) && !defined(OS_CHROMEOS)
+BPF_TEST_C(BaselinePolicy, FutexEINVAL, BaselinePolicy) {
+  int ops[] = {
+      FUTEX_CMP_REQUEUE_PI, FUTEX_CMP_REQUEUE_PI_PRIVATE,
+      FUTEX_UNLOCK_PI_PRIVATE,
+  };
+
+  for (int op : ops) {
+    BPF_ASSERT_EQ(-1, syscall(__NR_futex, NULL, op, 0, NULL, NULL, 0));
+    BPF_ASSERT_EQ(EINVAL, errno);
+  }
+}
+#else
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 FutexWithRequeuePriorityInheritence,
+                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI, 0, NULL, NULL, 0);
+  _exit(1);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 FutexWithRequeuePriorityInheritencePrivate,
+                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  syscall(__NR_futex, NULL, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, NULL, NULL, 0);
+  _exit(1);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 FutexWithUnlockPIPrivate,
+                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  syscall(__NR_futex, NULL, FUTEX_UNLOCK_PI_PRIVATE, 0, NULL, NULL, 0);
+  _exit(1);
+}
+#endif  // defined(LIBC_GLIBC) && !defined(OS_CHROMEOS)
+
+BPF_TEST_C(BaselinePolicy, PrctlDumpable, BaselinePolicy) {
+  const int is_dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
+  BPF_ASSERT(is_dumpable == 1 || is_dumpable == 0);
+  const int prctl_ret = prctl(PR_SET_DUMPABLE, is_dumpable, 0, 0, 0, 0);
+  BPF_ASSERT_EQ(0, prctl_ret);
+}
+
+// Workaround incomplete Android headers.
+#if !defined(PR_CAPBSET_READ)
+#define PR_CAPBSET_READ 23
+#endif
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 PrctlSigsys,
+                 DEATH_SEGV_MESSAGE(GetPrctlErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  prctl(PR_CAPBSET_READ, 0, 0, 0, 0);
+  _exit(1);
+}
+
+BPF_TEST_C(BaselinePolicy, GetOrSetPriority, BaselinePolicy) {
+  errno = 0;
+  const int original_prio = getpriority(PRIO_PROCESS, 0);
+  // Check errno instead of the return value since this system call can return
+  // -1 as a valid value.
+  BPF_ASSERT_EQ(0, errno);
+
+  errno = 0;
+  int rc = getpriority(PRIO_PROCESS, getpid());
+  BPF_ASSERT_EQ(0, errno);
+
+  rc = getpriority(PRIO_PROCESS, getpid() + 1);
+  BPF_ASSERT_EQ(-1, rc);
+  BPF_ASSERT_EQ(EPERM, errno);
+
+  rc = setpriority(PRIO_PROCESS, 0, original_prio);
+  BPF_ASSERT_EQ(0, rc);
+
+  rc = setpriority(PRIO_PROCESS, getpid(), original_prio);
+  BPF_ASSERT_EQ(0, rc);
+
+  errno = 0;
+  rc = setpriority(PRIO_PROCESS, getpid() + 1, original_prio);
+  BPF_ASSERT_EQ(-1, rc);
+  BPF_ASSERT_EQ(EPERM, errno);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 GetPrioritySigsys,
+                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  getpriority(PRIO_USER, 0);
+  _exit(1);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 ClockGettimeWithDisallowedClockCrashes,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+}
+
+#if !defined(__i386__)
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 GetSockOptWrongLevelSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  socklen_t peek_off_size = sizeof(id);
+  getsockopt(fds[0], IPPROTO_TCP, SO_PEEK_OFF, &id, &peek_off_size);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 GetSockOptWrongOptionSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  socklen_t peek_off_size = sizeof(id);
+  getsockopt(fds[0], SOL_SOCKET, SO_DEBUG, &id, &peek_off_size);
+}
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SetSockOptWrongLevelSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  setsockopt(fds[0], IPPROTO_TCP, SO_PEEK_OFF, &id, sizeof(id));
+}
+
+
+BPF_DEATH_TEST_C(BaselinePolicy,
+                 SetSockOptWrongOptionSigsys,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 BaselinePolicy) {
+  int fds[2];
+  PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+  int id;
+  setsockopt(fds[0], SOL_SOCKET, SO_DEBUG, &id, sizeof(id));
+}
+#endif
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/libchrome/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
new file mode 100644
index 0000000..077bc61
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -0,0 +1,299 @@
+// 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.
+
+// Note: any code in this file MUST be async-signal safe.
+
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+#if defined(__mips__)
+// __NR_Linux, is defined in <asm/unistd.h>.
+#include <asm/unistd.h>
+#endif
+
+#define SECCOMP_MESSAGE_COMMON_CONTENT "seccomp-bpf failure"
+#define SECCOMP_MESSAGE_CLONE_CONTENT "clone() failure"
+#define SECCOMP_MESSAGE_PRCTL_CONTENT "prctl() failure"
+#define SECCOMP_MESSAGE_IOCTL_CONTENT "ioctl() failure"
+#define SECCOMP_MESSAGE_KILL_CONTENT "(tg)kill() failure"
+#define SECCOMP_MESSAGE_FUTEX_CONTENT "futex() failure"
+
+namespace {
+
+inline bool IsArchitectureX86_64() {
+#if defined(__x86_64__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+// Write |error_message| to stderr. Similar to RawLog(), but a bit more careful
+// about async-signal safety. |size| is the size to write and should typically
+// not include a terminating \0.
+void WriteToStdErr(const char* error_message, size_t size) {
+  while (size > 0) {
+    // TODO(jln): query the current policy to check if send() is available and
+    // use it to perform a non-blocking write.
+    const int ret = HANDLE_EINTR(write(STDERR_FILENO, error_message, size));
+    // We can't handle any type of error here.
+    if (ret <= 0 || static_cast<size_t>(ret) > size) break;
+    size -= ret;
+    error_message += ret;
+  }
+}
+
+// Invalid syscall values are truncated to zero.
+// On architectures where base value is zero (Intel and Arm),
+// syscall number is the same as offset from base.
+// This function returns values between 0 and 1023 on all architectures.
+// On architectures where base value is different than zero (currently only
+// Mips), we are truncating valid syscall values to offset from base.
+uint32_t SyscallNumberToOffsetFromBase(uint32_t sysno) {
+#if defined(__mips__)
+  // On MIPS syscall numbers are in different range than on x86 and ARM.
+  // Valid MIPS O32 ABI syscall __NR_syscall will be truncated to zero for
+  // simplicity.
+  sysno = sysno - __NR_Linux;
+#endif
+
+  if (sysno >= 1024)
+    sysno = 0;
+
+  return sysno;
+}
+
+// Print a seccomp-bpf failure to handle |sysno| to stderr in an
+// async-signal safe way.
+void PrintSyscallError(uint32_t sysno) {
+  if (sysno >= 1024)
+    sysno = 0;
+  // TODO(markus): replace with async-signal safe snprintf when available.
+  const size_t kNumDigits = 4;
+  char sysno_base10[kNumDigits];
+  uint32_t rem = sysno;
+  uint32_t mod = 0;
+  for (int i = kNumDigits - 1; i >= 0; i--) {
+    mod = rem % 10;
+    rem /= 10;
+    sysno_base10[i] = '0' + mod;
+  }
+#if defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)
+  static const char kSeccompErrorPrefix[] = __FILE__
+      ":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall 4000 + ";
+#else
+  static const char kSeccompErrorPrefix[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall ";
+#endif
+  static const char kSeccompErrorPostfix[] = "\n";
+  WriteToStdErr(kSeccompErrorPrefix, sizeof(kSeccompErrorPrefix) - 1);
+  WriteToStdErr(sysno_base10, sizeof(sysno_base10));
+  WriteToStdErr(kSeccompErrorPostfix, sizeof(kSeccompErrorPostfix) - 1);
+}
+
+}  // namespace.
+
+namespace sandbox {
+
+intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux) {
+  uint32_t syscall = SyscallNumberToOffsetFromBase(args.nr);
+
+  PrintSyscallError(syscall);
+
+  // Encode 8-bits of the 1st two arguments too, so we can discern which socket
+  // type, which fcntl, ... etc., without being likely to hit a mapped
+  // address.
+  // Do not encode more bits here without thinking about increasing the
+  // likelihood of collision with mapped pages.
+  syscall |= ((args.args[0] & 0xffUL) << 12);
+  syscall |= ((args.args[1] & 0xffUL) << 20);
+  // Purposefully dereference the syscall as an address so it'll show up very
+  // clearly and easily in crash dumps.
+  volatile char* addr = reinterpret_cast<volatile char*>(syscall);
+  *addr = '\0';
+  // In case we hit a mapped address, hit the null page with just the syscall,
+  // for paranoia.
+  syscall &= 0xfffUL;
+  addr = reinterpret_cast<volatile char*>(syscall);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+// TODO(jln): refactor the reporting functions.
+
+intptr_t SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux) {
+  static const char kSeccompCloneError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_CLONE_CONTENT "\n";
+  WriteToStdErr(kSeccompCloneError, sizeof(kSeccompCloneError) - 1);
+  // "flags" is the first argument in the kernel's clone().
+  // Mark as volatile to be able to find the value on the stack in a minidump.
+  volatile uint64_t clone_flags = args.args[0];
+  volatile char* addr;
+  if (IsArchitectureX86_64()) {
+    addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFFFFF);
+    *addr = '\0';
+  }
+  // Hit the NULL page if this fails to fault.
+  addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSPrctlFailure(const struct arch_seccomp_data& args,
+                            void* /* aux */) {
+  static const char kSeccompPrctlError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_PRCTL_CONTENT "\n";
+  WriteToStdErr(kSeccompPrctlError, sizeof(kSeccompPrctlError) - 1);
+  // Mark as volatile to be able to find the value on the stack in a minidump.
+  volatile uint64_t option = args.args[0];
+  volatile char* addr =
+      reinterpret_cast<volatile char*>(option & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSIoctlFailure(const struct arch_seccomp_data& args,
+                            void* /* aux */) {
+  static const char kSeccompIoctlError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_IOCTL_CONTENT "\n";
+  WriteToStdErr(kSeccompIoctlError, sizeof(kSeccompIoctlError) - 1);
+  // Make "request" volatile so that we can see it on the stack in a minidump.
+  volatile uint64_t request = args.args[1];
+  volatile char* addr = reinterpret_cast<volatile char*>(request & 0xFFFF);
+  *addr = '\0';
+  // Hit the NULL page if this fails.
+  addr = reinterpret_cast<volatile char*>(request & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSKillFailure(const struct arch_seccomp_data& args,
+                           void* /* aux */) {
+   static const char kSeccompKillError[] =
+      __FILE__":**CRASHING**:" SECCOMP_MESSAGE_KILL_CONTENT "\n";
+  WriteToStdErr(kSeccompKillError, sizeof(kSeccompKillError) - 1);
+  // Make "pid" volatile so that we can see it on the stack in a minidump.
+  volatile uint64_t my_pid = sys_getpid();
+  volatile char* addr = reinterpret_cast<volatile char*>(my_pid & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args,
+                            void* /* aux */) {
+  static const char kSeccompFutexError[] =
+      __FILE__ ":**CRASHING**:" SECCOMP_MESSAGE_FUTEX_CONTENT "\n";
+  WriteToStdErr(kSeccompFutexError, sizeof(kSeccompFutexError) - 1);
+  volatile int futex_op = args.args[1];
+  volatile char* addr = reinterpret_cast<volatile char*>(futex_op & 0xFFF);
+  *addr = '\0';
+  for (;;)
+    _exit(1);
+}
+
+intptr_t SIGSYSSchedHandler(const struct arch_seccomp_data& args,
+                            void* aux) {
+  switch (args.nr) {
+    case __NR_sched_getaffinity:
+    case __NR_sched_getattr:
+    case __NR_sched_getparam:
+    case __NR_sched_getscheduler:
+    case __NR_sched_rr_get_interval:
+    case __NR_sched_setaffinity:
+    case __NR_sched_setattr:
+    case __NR_sched_setparam:
+    case __NR_sched_setscheduler:
+      const pid_t tid = sys_gettid();
+      // The first argument is the pid.  If is our thread id, then replace it
+      // with 0, which is equivalent and allowed by the policy.
+      if (args.args[0] == static_cast<uint64_t>(tid)) {
+        return Syscall::Call(args.nr,
+                             0,
+                             static_cast<intptr_t>(args.args[1]),
+                             static_cast<intptr_t>(args.args[2]),
+                             static_cast<intptr_t>(args.args[3]),
+                             static_cast<intptr_t>(args.args[4]),
+                             static_cast<intptr_t>(args.args[5]));
+      }
+      break;
+  }
+
+  CrashSIGSYS_Handler(args, aux);
+
+  // Should never be reached.
+  RAW_CHECK(false);
+  return -ENOSYS;
+}
+
+bpf_dsl::ResultExpr CrashSIGSYS() {
+  return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSClone() {
+  return bpf_dsl::Trap(SIGSYSCloneFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSPrctl() {
+  return bpf_dsl::Trap(SIGSYSPrctlFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSIoctl() {
+  return bpf_dsl::Trap(SIGSYSIoctlFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSKill() {
+  return bpf_dsl::Trap(SIGSYSKillFailure, NULL);
+}
+
+bpf_dsl::ResultExpr CrashSIGSYSFutex() {
+  return bpf_dsl::Trap(SIGSYSFutexFailure, NULL);
+}
+
+bpf_dsl::ResultExpr RewriteSchedSIGSYS() {
+  return bpf_dsl::Trap(SIGSYSSchedHandler, NULL);
+}
+
+const char* GetErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_COMMON_CONTENT;
+}
+
+const char* GetCloneErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_CLONE_CONTENT;
+}
+
+const char* GetPrctlErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_PRCTL_CONTENT;
+}
+
+const char* GetIoctlErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_IOCTL_CONTENT;
+}
+
+const char* GetKillErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_KILL_CONTENT;
+}
+
+const char* GetFutexErrorMessageContentForTests() {
+  return SECCOMP_MESSAGE_FUTEX_CONTENT;
+}
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h b/libchrome/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
new file mode 100644
index 0000000..c64e994
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
@@ -0,0 +1,82 @@
+// 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 SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SIGSYS_HANDLERS_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SIGSYS_HANDLERS_H_
+
+#include <stdint.h>
+
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/sandbox_export.h"
+
+// The handlers are suitable for use in Trap() error codes. They are
+// guaranteed to be async-signal safe.
+// See sandbox/linux/seccomp-bpf/trap.h to see how they work.
+
+namespace sandbox {
+
+struct arch_seccomp_data;
+
+// This handler will crash the currently running process. The crashing address
+// will be the number of the current system call, extracted from |args|.
+// This handler will also print to stderr the number of the crashing syscall.
+SANDBOX_EXPORT intptr_t
+    CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux);
+
+// The following three handlers are suitable to report failures with the
+// clone(), prctl() and ioctl() system calls respectively.
+
+// The crashing address will be (clone_flags & 0xFFFFFF), where clone_flags is
+// the clone(2) argument, extracted from |args|.
+SANDBOX_EXPORT intptr_t
+    SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be (option & 0xFFF), where option is the prctl(2)
+// argument.
+SANDBOX_EXPORT intptr_t
+    SIGSYSPrctlFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be request & 0xFFFF, where request is the ioctl(2)
+// argument.
+SANDBOX_EXPORT intptr_t
+    SIGSYSIoctlFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be (pid & 0xFFF), where pid is the first
+// argument (and can be a tid).
+SANDBOX_EXPORT intptr_t
+    SIGSYSKillFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be (op & 0xFFF), where op is the second
+// argument.
+SANDBOX_EXPORT intptr_t
+    SIGSYSFutexFailure(const struct arch_seccomp_data& args, void* aux);
+// If the syscall is not being called on the current tid, crashes in the same
+// way as CrashSIGSYS_Handler.  Otherwise, returns the result of calling the
+// syscall with the pid argument set to 0 (which for these calls means the
+// current thread).  The following syscalls are supported:
+//
+// sched_getaffinity(), sched_getattr(), sched_getparam(), sched_getscheduler(),
+// sched_rr_get_interval(), sched_setaffinity(), sched_setattr(),
+// sched_setparam(), sched_setscheduler()
+SANDBOX_EXPORT intptr_t
+    SIGSYSSchedHandler(const struct arch_seccomp_data& args, void* aux);
+
+// Variants of the above functions for use with bpf_dsl.
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYS();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSClone();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPrctl();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSIoctl();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex();
+SANDBOX_EXPORT bpf_dsl::ResultExpr RewriteSchedSIGSYS();
+
+// Following four functions return substrings of error messages used
+// in the above four functions. They are useful in death tests.
+SANDBOX_EXPORT const char* GetErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetCloneErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetPrctlErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetIoctlErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetKillErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetFutexErrorMessageContentForTests();
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SIGSYS_HANDLERS_H_
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
new file mode 100644
index 0000000..56c4cb3
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -0,0 +1,354 @@
+// 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 "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <linux/net.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/system_headers/linux_futex.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_time.h"
+
+// PNaCl toolchain does not provide sys/ioctl.h header.
+#if !defined(OS_NACL_NONSFI)
+#include <sys/ioctl.h>
+#endif
+
+#if defined(OS_ANDROID)
+
+#if !defined(F_DUPFD_CLOEXEC)
+#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6)
+#endif
+
+// https://android.googlesource.com/platform/bionic/+/lollipop-release/libc/private/bionic_prctl.h
+#if !defined(PR_SET_VMA)
+#define PR_SET_VMA 0x53564d41
+#endif
+
+#ifndef PR_SET_PTRACER
+#define PR_SET_PTRACER 0x59616d61
+#endif
+
+#endif  // defined(OS_ANDROID)
+
+#if defined(__arm__) && !defined(MAP_STACK)
+#define MAP_STACK 0x20000  // Daisy build environment has old headers.
+#endif
+
+#if defined(__mips__) && !defined(MAP_STACK)
+#define MAP_STACK 0x40000
+#endif
+namespace {
+
+inline bool IsArchitectureX86_64() {
+#if defined(__x86_64__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+inline bool IsArchitectureI386() {
+#if defined(__i386__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+inline bool IsAndroid() {
+#if defined(OS_ANDROID)
+  return true;
+#else
+  return false;
+#endif
+}
+
+inline bool IsArchitectureMips() {
+#if defined(__mips__)
+  return true;
+#else
+  return false;
+#endif
+}
+
+// Ubuntu's version of glibc has a race condition in sem_post that can cause
+// it to call futex(2) with bogus op arguments. To workaround this, we need
+// to allow those futex(2) calls to fail with EINVAL, instead of crashing the
+// process. See crbug.com/598471.
+inline bool IsBuggyGlibcSemPost() {
+#if defined(LIBC_GLIBC) && !defined(OS_CHROMEOS)
+  return true;
+#else
+  return false;
+#endif
+}
+
+}  // namespace.
+
+#define CASES SANDBOX_BPF_DSL_CASES
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Arg;
+using sandbox::bpf_dsl::BoolExpr;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::If;
+using sandbox::bpf_dsl::ResultExpr;
+
+namespace sandbox {
+
+#if !defined(OS_NACL_NONSFI)
+// Allow Glibc's and Android pthread creation flags, crash on any other
+// thread creation attempts and EPERM attempts to use neither
+// CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations.
+ResultExpr RestrictCloneToThreadsAndEPERMFork() {
+  const Arg<unsigned long> flags(0);
+
+  // TODO(mdempsky): Extend DSL to support (flags & ~mask1) == mask2.
+  const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES |
+                                     CLONE_SIGHAND | CLONE_THREAD |
+                                     CLONE_SYSVSEM;
+  const uint64_t kObsoleteAndroidCloneMask = kAndroidCloneMask | CLONE_DETACHED;
+
+  const uint64_t kGlibcPthreadFlags =
+      CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD |
+      CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
+  const BoolExpr glibc_test = flags == kGlibcPthreadFlags;
+
+  const BoolExpr android_test =
+      AnyOf(flags == kAndroidCloneMask, flags == kObsoleteAndroidCloneMask,
+            flags == kGlibcPthreadFlags);
+
+  return If(IsAndroid() ? android_test : glibc_test, Allow())
+      .ElseIf((flags & (CLONE_VM | CLONE_THREAD)) == 0, Error(EPERM))
+      .Else(CrashSIGSYSClone());
+}
+
+ResultExpr RestrictPrctl() {
+  // Will need to add seccomp compositing in the future. PR_SET_PTRACER is
+  // used by breakpad but not needed anymore.
+  const Arg<int> option(0);
+  return Switch(option)
+      .CASES((PR_GET_NAME, PR_SET_NAME, PR_GET_DUMPABLE, PR_SET_DUMPABLE
+#if defined(OS_ANDROID)
+              , PR_SET_VMA, PR_SET_PTRACER
+
+// Enable PR_SET_TIMERSLACK_PID, an Android custom prctl which is used in:
+// https://android.googlesource.com/platform/system/core/+/lollipop-release/libcutils/sched_policy.c.
+// Depending on the Android kernel version, this prctl may have different
+// values. Since we don't know the correct value for the running kernel, we must
+// allow them all.
+//
+// The effect is:
+// On 3.14 kernels, this allows PR_SET_TIMERSLACK_PID and 43 and 127 (invalid
+// prctls which will return EINVAL)
+// On 3.18 kernels, this allows PR_SET_TIMERSLACK_PID, PR_SET_THP_DISABLE, and
+// 127 (invalid).
+// On 4.1 kernels and up, this allows PR_SET_TIMERSLACK_PID, PR_SET_THP_DISABLE,
+// and PR_MPX_ENABLE_MANAGEMENT.
+
+// https://android.googlesource.com/kernel/common/+/android-3.14/include/uapi/linux/prctl.h
+#define PR_SET_TIMERSLACK_PID_1 41
+
+// https://android.googlesource.com/kernel/common/+/android-3.18/include/uapi/linux/prctl.h
+#define PR_SET_TIMERSLACK_PID_2 43
+
+// https://android.googlesource.com/kernel/common/+/android-4.1/include/uapi/linux/prctl.h and up
+#define PR_SET_TIMERSLACK_PID_3 127
+
+              , PR_SET_TIMERSLACK_PID_1
+              , PR_SET_TIMERSLACK_PID_2
+              , PR_SET_TIMERSLACK_PID_3
+#endif  // defined(OS_ANDROID)
+              ),
+             Allow())
+      .Default(CrashSIGSYSPrctl());
+}
+
+ResultExpr RestrictIoctl() {
+  const Arg<int> request(1);
+  return Switch(request).CASES((TCGETS, FIONREAD), Allow()).Default(
+      CrashSIGSYSIoctl());
+}
+
+ResultExpr RestrictMmapFlags() {
+  // The flags you see are actually the allowed ones, and the variable is a
+  // "denied" mask because of the negation operator.
+  // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as
+  // MAP_POPULATE.
+  // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries.
+  const uint64_t kAllowedMask = MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
+                                MAP_STACK | MAP_NORESERVE | MAP_FIXED |
+                                MAP_DENYWRITE;
+  const Arg<int> flags(3);
+  return If((flags & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
+}
+
+ResultExpr RestrictMprotectFlags() {
+  // The flags you see are actually the allowed ones, and the variable is a
+  // "denied" mask because of the negation operator.
+  // Significantly, we don't permit weird undocumented flags such as
+  // PROT_GROWSDOWN.
+  const uint64_t kAllowedMask = PROT_READ | PROT_WRITE | PROT_EXEC;
+  const Arg<int> prot(2);
+  return If((prot & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS());
+}
+
+ResultExpr RestrictFcntlCommands() {
+  // We also restrict the flags in F_SETFL. We don't want to permit flags with
+  // a history of trouble such as O_DIRECT. The flags you see are actually the
+  // allowed ones, and the variable is a "denied" mask because of the negation
+  // operator.
+  // Glibc overrides the kernel's O_LARGEFILE value. Account for this.
+  uint64_t kOLargeFileFlag = O_LARGEFILE;
+  if (IsArchitectureX86_64() || IsArchitectureI386() || IsArchitectureMips())
+    kOLargeFileFlag = 0100000;
+
+  const Arg<int> cmd(1);
+  const Arg<long> long_arg(2);
+
+  const uint64_t kAllowedMask = O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC |
+                                kOLargeFileFlag | O_CLOEXEC | O_NOATIME;
+  return Switch(cmd)
+      .CASES((F_GETFL,
+              F_GETFD,
+              F_SETFD,
+              F_SETLK,
+              F_SETLKW,
+              F_GETLK,
+              F_DUPFD,
+              F_DUPFD_CLOEXEC),
+             Allow())
+      .Case(F_SETFL,
+            If((long_arg & ~kAllowedMask) == 0, Allow()).Else(CrashSIGSYS()))
+      .Default(CrashSIGSYS());
+}
+
+#if defined(__i386__) || defined(__mips__)
+ResultExpr RestrictSocketcallCommand() {
+  // Unfortunately, we are unable to restrict the first parameter to
+  // socketpair(2). Whilst initially sounding bad, it's noteworthy that very
+  // few protocols actually support socketpair(2). The scary call that we're
+  // worried about, socket(2), remains blocked.
+  const Arg<int> call(0);
+  return Switch(call)
+      .CASES((SYS_SOCKETPAIR,
+              SYS_SHUTDOWN,
+              SYS_RECV,
+              SYS_SEND,
+              SYS_RECVFROM,
+              SYS_SENDTO,
+              SYS_RECVMSG,
+              SYS_SENDMSG),
+             Allow())
+      .Default(Error(EPERM));
+}
+#endif
+
+ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) {
+  switch (sysno) {
+    case __NR_kill:
+    case __NR_tgkill: {
+      const Arg<pid_t> pid(0);
+      return If(pid == target_pid, Allow()).Else(CrashSIGSYSKill());
+    }
+    case __NR_tkill:
+      return CrashSIGSYSKill();
+    default:
+      NOTREACHED();
+      return CrashSIGSYS();
+  }
+}
+
+ResultExpr RestrictFutex() {
+  const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME;
+  const Arg<int> op(1);
+  return Switch(op & ~kAllowedFutexFlags)
+      .CASES((FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE, FUTEX_CMP_REQUEUE,
+              FUTEX_WAKE_OP, FUTEX_WAIT_BITSET, FUTEX_WAKE_BITSET),
+             Allow())
+      .Default(IsBuggyGlibcSemPost() ? Error(EINVAL) : CrashSIGSYSFutex());
+}
+
+ResultExpr RestrictGetSetpriority(pid_t target_pid) {
+  const Arg<int> which(0);
+  const Arg<int> who(1);
+  return If(which == PRIO_PROCESS,
+            Switch(who).CASES((0, target_pid), Allow()).Default(Error(EPERM)))
+      .Else(CrashSIGSYS());
+}
+
+ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) {
+  switch (sysno) {
+    case __NR_sched_getaffinity:
+    case __NR_sched_getattr:
+    case __NR_sched_getparam:
+    case __NR_sched_getscheduler:
+    case __NR_sched_rr_get_interval:
+    case __NR_sched_setaffinity:
+    case __NR_sched_setattr:
+    case __NR_sched_setparam:
+    case __NR_sched_setscheduler: {
+      const Arg<pid_t> pid(0);
+      return Switch(pid)
+          .CASES((0, target_pid), Allow())
+          .Default(RewriteSchedSIGSYS());
+    }
+    default:
+      NOTREACHED();
+      return CrashSIGSYS();
+  }
+}
+
+ResultExpr RestrictPrlimit64(pid_t target_pid) {
+  const Arg<pid_t> pid(0);
+  return Switch(pid).CASES((0, target_pid), Allow()).Default(CrashSIGSYS());
+}
+
+ResultExpr RestrictGetrusage() {
+  const Arg<int> who(0);
+  return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS());
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+ResultExpr RestrictClockID() {
+  static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit");
+  const Arg<clockid_t> clockid(0);
+  return Switch(clockid)
+      .CASES((
+#if defined(OS_ANDROID)
+              CLOCK_BOOTTIME,
+#endif
+              CLOCK_MONOTONIC,
+              CLOCK_MONOTONIC_COARSE,
+              CLOCK_PROCESS_CPUTIME_ID,
+              CLOCK_REALTIME,
+              CLOCK_REALTIME_COARSE,
+              CLOCK_THREAD_CPUTIME_ID),
+             Allow())
+      .Default(CrashSIGSYS());
+}
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
new file mode 100644
index 0000000..b96fe20
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -0,0 +1,99 @@
+// 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 SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
+
+#include <unistd.h>
+
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/sandbox_export.h"
+
+// These are helpers to build seccomp-bpf policies, i.e. policies for a
+// sandbox that reduces the Linux kernel's attack surface. They return a
+// bpf_dsl::ResultExpr suitable to restrict certain system call parameters.
+
+namespace sandbox {
+
+// Allow clone(2) for threads.
+// Reject fork(2) attempts with EPERM.
+// Don't restrict on ASAN.
+// Crash if anything else is attempted.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictCloneToThreadsAndEPERMFork();
+
+// Allow PR_SET_NAME, PR_SET_DUMPABLE, PR_GET_DUMPABLE.
+// Crash if anything else is attempted.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrctl();
+
+// Allow TCGETS and FIONREAD.
+// Crash if anything else is attempted.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictIoctl();
+
+// Restrict the flags argument in mmap(2).
+// Only allow: MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
+// MAP_STACK | MAP_NORESERVE | MAP_FIXED | MAP_DENYWRITE.
+// Crash if any other flag is used.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMmapFlags();
+
+// Restrict the prot argument in mprotect(2).
+// Only allow: PROT_READ | PROT_WRITE | PROT_EXEC.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictMprotectFlags();
+
+// Restrict fcntl(2) cmd argument to:
+// We allow F_GETFL, F_SETFL, F_GETFD, F_SETFD, F_DUPFD, F_DUPFD_CLOEXEC,
+// F_SETLK, F_SETLKW and F_GETLK.
+// Also, in F_SETFL, restrict the allowed flags to: O_ACCMODE | O_APPEND |
+// O_NONBLOCK | O_SYNC | O_LARGEFILE | O_CLOEXEC | O_NOATIME.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictFcntlCommands();
+
+#if defined(__i386__) || defined(__mips__)
+// Restrict socketcall(2) to only allow socketpair(2), send(2), recv(2),
+// sendto(2), recvfrom(2), shutdown(2), sendmsg(2) and recvmsg(2).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictSocketcallCommand();
+#endif
+
+// Restrict |sysno| (which must be kill, tkill or tgkill) by allowing tgkill or
+// kill iff the first parameter is |target_pid|, crashing otherwise or if
+// |sysno| is tkill.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictKillTarget(pid_t target_pid,
+                                                      int sysno);
+
+// Crash if FUTEX_CMP_REQUEUE_PI is used in the second argument of futex(2).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictFutex();
+
+// Crash if |which| is not PRIO_PROCESS. EPERM if |who| is not 0, neither
+// |target_pid| while calling setpriority(2) / getpriority(2).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid);
+
+// Restricts |pid| for sched_* syscalls which take a pid as the first argument.
+// We only allow calling these syscalls if the pid argument is equal to the pid
+// of the sandboxed process or 0 (indicating the current thread).  The following
+// syscalls are supported:
+//
+// sched_getaffinity(), sched_getattr(), sched_getparam(), sched_getscheduler(),
+// sched_rr_get_interval(), sched_setaffinity(), sched_setattr(),
+// sched_setparam(), sched_setscheduler()
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictSchedTarget(pid_t target_pid,
+                                                       int sysno);
+
+// Restricts the |pid| argument of prlimit64 to 0 (meaning the calling process)
+// or target_pid.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimit64(pid_t target_pid);
+
+// Restricts the |who| argument of getrusage to RUSAGE_SELF (meaning the calling
+// process).
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetrusage();
+
+// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime().
+// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID.  In particular, this disallows
+// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those
+// returned by {clock,pthread}_getcpuclockid), which can leak information
+// about the state of the host OS.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID();
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
new file mode 100644
index 0000000..804a8fe
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
@@ -0,0 +1,241 @@
+// 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 "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/sys_info.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/system_headers/linux_time.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+#if !defined(OS_ANDROID)
+#include "third_party/lss/linux_syscall_support.h"  // for MAKE_PROCESS_CPUCLOCK
+#endif
+
+namespace sandbox {
+
+namespace {
+
+// NOTE: most of the parameter restrictions are tested in
+// baseline_policy_unittest.cc as a more end-to-end test.
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::ResultExpr;
+
+class RestrictClockIdPolicy : public bpf_dsl::Policy {
+ public:
+  RestrictClockIdPolicy() {}
+  ~RestrictClockIdPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_clock_gettime:
+      case __NR_clock_getres:
+        return RestrictClockID();
+      default:
+        return Allow();
+    }
+  }
+};
+
+void CheckClock(clockid_t clockid) {
+  struct timespec ts;
+  ts.tv_sec = -1;
+  ts.tv_nsec = -1;
+  BPF_ASSERT_EQ(0, clock_getres(clockid, &ts));
+  BPF_ASSERT_EQ(0, ts.tv_sec);
+  BPF_ASSERT_LE(0, ts.tv_nsec);
+  ts.tv_sec = -1;
+  ts.tv_nsec = -1;
+  BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts));
+  BPF_ASSERT_LE(0, ts.tv_sec);
+  BPF_ASSERT_LE(0, ts.tv_nsec);
+}
+
+BPF_TEST_C(ParameterRestrictions,
+           clock_gettime_allowed,
+           RestrictClockIdPolicy) {
+  CheckClock(CLOCK_MONOTONIC);
+  CheckClock(CLOCK_MONOTONIC_COARSE);
+  CheckClock(CLOCK_PROCESS_CPUTIME_ID);
+#if defined(OS_ANDROID)
+  CheckClock(CLOCK_BOOTTIME);
+#endif
+  CheckClock(CLOCK_REALTIME);
+  CheckClock(CLOCK_REALTIME_COARSE);
+  CheckClock(CLOCK_THREAD_CPUTIME_ID);
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 clock_gettime_crash_monotonic_raw,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictClockIdPolicy) {
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+}
+
+#if !defined(OS_ANDROID)
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 clock_gettime_crash_cpu_clock,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictClockIdPolicy) {
+  // We can't use clock_getcpuclockid() because it's not implemented in newlib,
+  // and it might not work inside the sandbox anyway.
+  const pid_t kInitPID = 1;
+  const clockid_t kInitCPUClockID =
+      MAKE_PROCESS_CPUCLOCK(kInitPID, CPUCLOCK_SCHED);
+
+  struct timespec ts;
+  clock_gettime(kInitCPUClockID, &ts);
+}
+#endif  // !defined(OS_ANDROID)
+
+class RestrictSchedPolicy : public bpf_dsl::Policy {
+ public:
+  RestrictSchedPolicy() {}
+  ~RestrictSchedPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_sched_getparam:
+        return RestrictSchedTarget(getpid(), sysno);
+      default:
+        return Allow();
+    }
+  }
+};
+
+void CheckSchedGetParam(pid_t pid, struct sched_param* param) {
+  BPF_ASSERT_EQ(0, sched_getparam(pid, param));
+}
+
+void SchedGetParamThread(base::WaitableEvent* thread_run) {
+  const pid_t pid = getpid();
+  const pid_t tid = sys_gettid();
+  BPF_ASSERT_NE(pid, tid);
+
+  struct sched_param current_pid_param;
+  CheckSchedGetParam(pid, &current_pid_param);
+
+  struct sched_param zero_param;
+  CheckSchedGetParam(0, &zero_param);
+
+  struct sched_param tid_param;
+  CheckSchedGetParam(tid, &tid_param);
+
+  BPF_ASSERT_EQ(zero_param.sched_priority, tid_param.sched_priority);
+
+  // Verify that the SIGSYS handler sets errno properly.
+  errno = 0;
+  BPF_ASSERT_EQ(-1, sched_getparam(tid, NULL));
+  BPF_ASSERT_EQ(EINVAL, errno);
+
+  thread_run->Signal();
+}
+
+BPF_TEST_C(ParameterRestrictions,
+           sched_getparam_allowed,
+           RestrictSchedPolicy) {
+  base::WaitableEvent thread_run(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  // Run the actual test in a new thread so that the current pid and tid are
+  // different.
+  base::Thread getparam_thread("sched_getparam_thread");
+  BPF_ASSERT(getparam_thread.Start());
+  getparam_thread.message_loop()->PostTask(
+      FROM_HERE, base::Bind(&SchedGetParamThread, &thread_run));
+  BPF_ASSERT(thread_run.TimedWait(base::TimeDelta::FromMilliseconds(5000)));
+  getparam_thread.Stop();
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 sched_getparam_crash_non_zero,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictSchedPolicy) {
+  const pid_t kInitPID = 1;
+  struct sched_param param;
+  sched_getparam(kInitPID, &param);
+}
+
+class RestrictPrlimit64Policy : public bpf_dsl::Policy {
+ public:
+  RestrictPrlimit64Policy() {}
+  ~RestrictPrlimit64Policy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_prlimit64:
+        return RestrictPrlimit64(getpid());
+      default:
+        return Allow();
+    }
+  }
+};
+
+BPF_TEST_C(ParameterRestrictions, prlimit64_allowed, RestrictPrlimit64Policy) {
+  BPF_ASSERT_EQ(0, sys_prlimit64(0, RLIMIT_AS, NULL, NULL));
+  BPF_ASSERT_EQ(0, sys_prlimit64(getpid(), RLIMIT_AS, NULL, NULL));
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 prlimit64_crash_not_self,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictPrlimit64Policy) {
+  const pid_t kInitPID = 1;
+  BPF_ASSERT_NE(kInitPID, getpid());
+  sys_prlimit64(kInitPID, RLIMIT_AS, NULL, NULL);
+}
+
+class RestrictGetrusagePolicy : public bpf_dsl::Policy {
+ public:
+  RestrictGetrusagePolicy() {}
+  ~RestrictGetrusagePolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      case __NR_getrusage:
+        return RestrictGetrusage();
+      default:
+        return Allow();
+    }
+  }
+};
+
+BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) {
+  struct rusage usage;
+  BPF_ASSERT_EQ(0, getrusage(RUSAGE_SELF, &usage));
+}
+
+BPF_DEATH_TEST_C(ParameterRestrictions,
+                 getrusage_crash_not_self,
+                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
+                 RestrictGetrusagePolicy) {
+  struct rusage usage;
+  getrusage(RUSAGE_CHILDREN, &usage);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
new file mode 100644
index 0000000..c217d47
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc
@@ -0,0 +1,1060 @@
+// 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 "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h"
+
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+// The functions below cover all existing i386, x86_64, and ARM system calls;
+// excluding syscalls made obsolete in ARM EABI.
+// The implicitly defined sets form a partition of the sets of
+// system calls.
+
+bool SyscallSets::IsKill(int sysno) {
+  switch (sysno) {
+    case __NR_kill:
+    case __NR_tgkill:
+    case __NR_tkill:  // Deprecated.
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedGettime(int sysno) {
+  switch (sysno) {
+    case __NR_gettimeofday:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_time:
+#endif
+      return true;
+    case __NR_adjtimex:         // Privileged.
+    case __NR_clock_adjtime:    // Privileged.
+    case __NR_clock_getres:     // Could be allowed.
+    case __NR_clock_gettime:
+    case __NR_clock_nanosleep:  // Could be allowed.
+    case __NR_clock_settime:    // Privileged.
+#if defined(__i386__) || defined(__mips__)
+    case __NR_ftime:  // Obsolete.
+#endif
+    case __NR_settimeofday:  // Privileged.
+#if defined(__i386__) || defined(__mips__)
+    case __NR_stime:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsCurrentDirectory(int sysno) {
+  switch (sysno) {
+    case __NR_getcwd:
+    case __NR_chdir:
+    case __NR_fchdir:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsUmask(int sysno) {
+  switch (sysno) {
+    case __NR_umask:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// System calls that directly access the file system. They might acquire
+// a new file descriptor or otherwise perform an operation directly
+// via a path.
+// Both EPERM and ENOENT are valid errno unless otherwise noted in comment.
+bool SyscallSets::IsFileSystem(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_access:  // EPERM not a valid errno.
+    case __NR_chmod:
+    case __NR_chown:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_chown32:
+#endif
+    case __NR_creat:
+    case __NR_futimesat:  // Should be called utimesat ?
+    case __NR_lchown:
+    case __NR_link:
+    case __NR_lstat:  // EPERM not a valid errno.
+    case __NR_mkdir:
+    case __NR_mknod:
+    case __NR_open:
+    case __NR_readlink:  // EPERM not a valid errno.
+    case __NR_rename:
+    case __NR_rmdir:
+    case __NR_stat:  // EPERM not a valid errno.
+    case __NR_symlink:
+    case __NR_unlink:
+    case __NR_uselib:  // Neither EPERM, nor ENOENT are valid errno.
+    case __NR_ustat:   // Same as above. Deprecated.
+    case __NR_utimes:
+#endif  // !defined(__aarch64__)
+
+    case __NR_execve:
+    case __NR_faccessat:  // EPERM not a valid errno.
+    case __NR_fchmodat:
+    case __NR_fchownat:  // Should be called chownat ?
+#if defined(__x86_64__) || defined(__aarch64__)
+    case __NR_newfstatat:  // fstatat(). EPERM not a valid errno.
+#elif defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fstatat64:
+#endif
+#if defined(__i386__) || defined(__arm__)
+    case __NR_lchown32:
+#endif
+    case __NR_linkat:
+    case __NR_lookup_dcookie:  // ENOENT not a valid errno.
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_lstat64:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
+    case __NR_memfd_create:
+#endif
+    case __NR_mkdirat:
+    case __NR_mknodat:
+#if defined(__i386__)
+    case __NR_oldlstat:
+    case __NR_oldstat:
+#endif
+    case __NR_openat:
+    case __NR_readlinkat:
+    case __NR_renameat:
+    case __NR_renameat2:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_stat64:
+#endif
+    case __NR_statfs:  // EPERM not a valid errno.
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_statfs64:
+#endif
+    case __NR_symlinkat:
+    case __NR_truncate:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_truncate64:
+#endif
+    case __NR_unlinkat:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_utime:
+#endif
+    case __NR_utimensat:  // New.
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedFileSystemAccessViaFd(int sysno) {
+  switch (sysno) {
+    case __NR_fstat:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fstat64:
+#endif
+      return true;
+// TODO(jln): these should be denied gracefully as well (moved below).
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_fadvise64:  // EPERM not a valid errno.
+#endif
+#if defined(__i386__)
+    case __NR_fadvise64_64:
+#endif
+#if defined(__arm__)
+    case __NR_arm_fadvise64_64:
+#endif
+    case __NR_fdatasync:  // EPERM not a valid errno.
+    case __NR_flock:      // EPERM not a valid errno.
+    case __NR_fstatfs:    // Give information about the whole filesystem.
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fstatfs64:
+#endif
+    case __NR_fsync:  // EPERM not a valid errno.
+#if defined(__i386__)
+    case __NR_oldfstat:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_sync_file_range:  // EPERM not a valid errno.
+#elif defined(__arm__)
+    case __NR_arm_sync_file_range:  // EPERM not a valid errno.
+#endif
+    default:
+      return false;
+  }
+}
+
+// EPERM is a good errno for any of these.
+bool SyscallSets::IsDeniedFileSystemAccessViaFd(int sysno) {
+  switch (sysno) {
+    case __NR_fallocate:
+    case __NR_fchmod:
+    case __NR_fchown:
+    case __NR_ftruncate:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_fchown32:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_ftruncate64:
+#endif
+#if !defined(__aarch64__)
+    case __NR_getdents:    // EPERM not a valid errno.
+#endif
+    case __NR_getdents64:  // EPERM not a valid errno.
+#if defined(__i386__) || defined(__mips__)
+    case __NR_readdir:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGetSimpleId(int sysno) {
+  switch (sysno) {
+    case __NR_capget:
+    case __NR_getegid:
+    case __NR_geteuid:
+    case __NR_getgid:
+    case __NR_getgroups:
+    case __NR_getpid:
+    case __NR_getppid:
+    case __NR_getresgid:
+    case __NR_getsid:
+    case __NR_gettid:
+    case __NR_getuid:
+    case __NR_getresuid:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_getegid32:
+    case __NR_geteuid32:
+    case __NR_getgid32:
+    case __NR_getgroups32:
+    case __NR_getresgid32:
+    case __NR_getresuid32:
+    case __NR_getuid32:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsProcessPrivilegeChange(int sysno) {
+  switch (sysno) {
+    case __NR_capset:
+#if defined(__i386__) || defined(__x86_64__)
+    case __NR_ioperm:  // Intel privilege.
+    case __NR_iopl:    // Intel privilege.
+#endif
+    case __NR_setfsgid:
+    case __NR_setfsuid:
+    case __NR_setgid:
+    case __NR_setgroups:
+    case __NR_setregid:
+    case __NR_setresgid:
+    case __NR_setresuid:
+    case __NR_setreuid:
+    case __NR_setuid:
+#if defined(__i386__) || defined(__arm__)
+    case __NR_setfsgid32:
+    case __NR_setfsuid32:
+    case __NR_setgid32:
+    case __NR_setgroups32:
+    case __NR_setregid32:
+    case __NR_setresgid32:
+    case __NR_setresuid32:
+    case __NR_setreuid32:
+    case __NR_setuid32:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsProcessGroupOrSession(int sysno) {
+  switch (sysno) {
+    case __NR_setpgid:
+#if !defined(__aarch64__)
+    case __NR_getpgrp:
+#endif
+    case __NR_setsid:
+    case __NR_getpgid:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedSignalHandling(int sysno) {
+  switch (sysno) {
+    case __NR_rt_sigaction:
+    case __NR_rt_sigprocmask:
+    case __NR_rt_sigreturn:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_sigaction:
+    case __NR_sigprocmask:
+    case __NR_sigreturn:
+#endif
+      return true;
+    case __NR_rt_sigpending:
+    case __NR_rt_sigqueueinfo:
+    case __NR_rt_sigsuspend:
+    case __NR_rt_sigtimedwait:
+    case __NR_rt_tgsigqueueinfo:
+    case __NR_sigaltstack:
+#if !defined(__aarch64__)
+    case __NR_signalfd:
+#endif
+    case __NR_signalfd4:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_sigpending:
+    case __NR_sigsuspend:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_signal:
+    case __NR_sgetmask:  // Obsolete.
+    case __NR_ssetmask:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedOperationOnFd(int sysno) {
+  switch (sysno) {
+    case __NR_close:
+    case __NR_dup:
+#if !defined(__aarch64__)
+    case __NR_dup2:
+#endif
+    case __NR_dup3:
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_shutdown:
+#endif
+      return true;
+    case __NR_fcntl:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_fcntl64:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsKernelInternalApi(int sysno) {
+  switch (sysno) {
+    case __NR_restart_syscall:
+#if defined(__arm__)
+    case __ARM_NR_cmpxchg:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+// This should be thought through in conjunction with IsFutex().
+bool SyscallSets::IsAllowedProcessStartOrDeath(int sysno) {
+  switch (sysno) {
+    case __NR_exit:
+    case __NR_exit_group:
+    case __NR_wait4:
+    case __NR_waitid:
+#if defined(__i386__)
+    case __NR_waitpid:
+#endif
+      return true;
+    case __NR_clone:  // Should be parameter-restricted.
+    case __NR_setns:  // Privileged.
+#if !defined(__aarch64__)
+    case __NR_fork:
+#endif
+#if defined(__i386__) || defined(__x86_64__)
+    case __NR_get_thread_area:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_set_thread_area:
+#endif
+    case __NR_set_tid_address:
+    case __NR_unshare:
+#if !defined(__mips__) && !defined(__aarch64__)
+    case __NR_vfork:
+#endif
+    default:
+      return false;
+  }
+}
+
+// It's difficult to restrict those, but there is attack surface here.
+bool SyscallSets::IsAllowedFutex(int sysno) {
+  switch (sysno) {
+    case __NR_get_robust_list:
+    case __NR_set_robust_list:
+    case __NR_futex:
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedEpoll(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_epoll_create:
+    case __NR_epoll_wait:
+#endif
+    case __NR_epoll_create1:
+    case __NR_epoll_ctl:
+      return true;
+    default:
+#if defined(__x86_64__)
+    case __NR_epoll_ctl_old:
+#endif
+    case __NR_epoll_pwait:
+#if defined(__x86_64__)
+    case __NR_epoll_wait_old:
+#endif
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedGetOrModifySocket(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_pipe:
+#endif
+    case __NR_pipe2:
+      return true;
+    default:
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_socketpair:  // We will want to inspect its argument.
+#endif
+      return false;
+  }
+}
+
+bool SyscallSets::IsDeniedGetOrModifySocket(int sysno) {
+  switch (sysno) {
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_accept:
+    case __NR_accept4:
+    case __NR_bind:
+    case __NR_connect:
+    case __NR_socket:
+    case __NR_listen:
+      return true;
+#endif
+    default:
+      return false;
+  }
+}
+
+#if defined(__i386__) || defined(__mips__)
+// Big multiplexing system call for sockets.
+bool SyscallSets::IsSocketCall(int sysno) {
+  switch (sysno) {
+    case __NR_socketcall:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__)
+bool SyscallSets::IsNetworkSocketInformation(int sysno) {
+  switch (sysno) {
+    case __NR_getpeername:
+    case __NR_getsockname:
+    case __NR_getsockopt:
+    case __NR_setsockopt:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+bool SyscallSets::IsAllowedAddressSpaceAccess(int sysno) {
+  switch (sysno) {
+    case __NR_brk:
+    case __NR_mlock:
+    case __NR_munlock:
+    case __NR_munmap:
+      return true;
+    case __NR_madvise:
+    case __NR_mincore:
+    case __NR_mlockall:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_mmap:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_mmap2:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_modify_ldt:
+#endif
+    case __NR_mprotect:
+    case __NR_mremap:
+    case __NR_msync:
+    case __NR_munlockall:
+    case __NR_readahead:
+    case __NR_remap_file_pages:
+#if defined(__i386__)
+    case __NR_vm86:
+    case __NR_vm86old:
+#endif
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedGeneralIo(int sysno) {
+  switch (sysno) {
+    case __NR_lseek:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR__llseek:
+#endif
+#if !defined(__aarch64__)
+    case __NR_poll:
+#endif
+    case __NR_ppoll:
+    case __NR_pselect6:
+    case __NR_read:
+    case __NR_readv:
+#if defined(__arm__) || defined(__mips__)
+    case __NR_recv:
+#endif
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_recvfrom:  // Could specify source.
+    case __NR_recvmsg:   // Could specify source.
+#endif
+#if defined(__i386__) || defined(__x86_64__)
+    case __NR_select:
+#endif
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR__newselect:
+#endif
+#if defined(__arm__)
+    case __NR_send:
+#endif
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_sendmsg:  // Could specify destination.
+    case __NR_sendto:   // Could specify destination.
+#endif
+    case __NR_write:
+    case __NR_writev:
+      return true;
+    case __NR_ioctl:  // Can be very powerful.
+    case __NR_pread64:
+    case __NR_preadv:
+    case __NR_pwrite64:
+    case __NR_pwritev:
+    case __NR_recvmmsg:  // Could specify source.
+    case __NR_sendfile:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_sendfile64:
+#endif
+    case __NR_sendmmsg:  // Could specify destination.
+    case __NR_splice:
+    case __NR_tee:
+    case __NR_vmsplice:
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsPrctl(int sysno) {
+  switch (sysno) {
+#if defined(__x86_64__)
+    case __NR_arch_prctl:
+#endif
+    case __NR_prctl:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsSeccomp(int sysno) {
+  switch (sysno) {
+    case __NR_seccomp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAllowedBasicScheduler(int sysno) {
+  switch (sysno) {
+    case __NR_sched_yield:
+#if !defined(__aarch64__)
+    case __NR_pause:
+#endif
+    case __NR_nanosleep:
+      return true;
+    case __NR_getpriority:
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_nice:
+#endif
+    case __NR_setpriority:
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAdminOperation(int sysno) {
+  switch (sysno) {
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+    case __NR_bdflush:
+#endif
+    case __NR_kexec_load:
+    case __NR_reboot:
+    case __NR_setdomainname:
+    case __NR_sethostname:
+    case __NR_syslog:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsKernelModule(int sysno) {
+  switch (sysno) {
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_create_module:
+    case __NR_get_kernel_syms:  // Should ENOSYS.
+    case __NR_query_module:
+#endif
+    case __NR_delete_module:
+    case __NR_init_module:
+    case __NR_finit_module:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGlobalFSViewChange(int sysno) {
+  switch (sysno) {
+    case __NR_pivot_root:
+    case __NR_chroot:
+    case __NR_sync:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsFsControl(int sysno) {
+  switch (sysno) {
+    case __NR_mount:
+    case __NR_nfsservctl:
+    case __NR_quotactl:
+    case __NR_swapoff:
+    case __NR_swapon:
+#if defined(__i386__) || defined(__mips__)
+    case __NR_umount:
+#endif
+    case __NR_umount2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsNuma(int sysno) {
+  switch (sysno) {
+    case __NR_get_mempolicy:
+    case __NR_getcpu:
+    case __NR_mbind:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_migrate_pages:
+#endif
+    case __NR_move_pages:
+    case __NR_set_mempolicy:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsMessageQueue(int sysno) {
+  switch (sysno) {
+    case __NR_mq_getsetattr:
+    case __NR_mq_notify:
+    case __NR_mq_open:
+    case __NR_mq_timedreceive:
+    case __NR_mq_timedsend:
+    case __NR_mq_unlink:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGlobalProcessEnvironment(int sysno) {
+  switch (sysno) {
+    case __NR_acct:  // Privileged.
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) || \
+    defined(__aarch64__)
+    case __NR_getrlimit:
+#endif
+#if defined(__i386__) || defined(__arm__)
+    case __NR_ugetrlimit:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_ulimit:
+#endif
+    case __NR_getrusage:
+    case __NR_personality:  // Can change its personality as well.
+    case __NR_prlimit64:    // Like setrlimit / getrlimit.
+    case __NR_setrlimit:
+    case __NR_times:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsDebug(int sysno) {
+  switch (sysno) {
+    case __NR_ptrace:
+    case __NR_process_vm_readv:
+    case __NR_process_vm_writev:
+    case __NR_kcmp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsGlobalSystemStatus(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR__sysctl:
+    case __NR_sysfs:
+#endif
+    case __NR_sysinfo:
+    case __NR_uname:
+#if defined(__i386__)
+    case __NR_olduname:
+    case __NR_oldolduname:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsEventFd(int sysno) {
+  switch (sysno) {
+#if !defined(__aarch64__)
+    case __NR_eventfd:
+#endif
+    case __NR_eventfd2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Asynchronous I/O API.
+bool SyscallSets::IsAsyncIo(int sysno) {
+  switch (sysno) {
+    case __NR_io_cancel:
+    case __NR_io_destroy:
+    case __NR_io_getevents:
+    case __NR_io_setup:
+    case __NR_io_submit:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsKeyManagement(int sysno) {
+  switch (sysno) {
+    case __NR_add_key:
+    case __NR_keyctl:
+    case __NR_request_key:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+bool SyscallSets::IsSystemVSemaphores(int sysno) {
+  switch (sysno) {
+    case __NR_semctl:
+    case __NR_semget:
+    case __NR_semop:
+    case __NR_semtimedop:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+// These give a lot of ambient authority and bypass the setuid sandbox.
+bool SyscallSets::IsSystemVSharedMemory(int sysno) {
+  switch (sysno) {
+    case __NR_shmat:
+    case __NR_shmctl:
+    case __NR_shmdt:
+    case __NR_shmget:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+bool SyscallSets::IsSystemVMessageQueue(int sysno) {
+  switch (sysno) {
+    case __NR_msgctl:
+    case __NR_msgget:
+    case __NR_msgrcv:
+    case __NR_msgsnd:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+#if defined(__i386__) || defined(__mips__)
+// Big system V multiplexing system call.
+bool SyscallSets::IsSystemVIpc(int sysno) {
+  switch (sysno) {
+    case __NR_ipc:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif
+
+bool SyscallSets::IsAnySystemV(int sysno) {
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  return IsSystemVMessageQueue(sysno) || IsSystemVSemaphores(sysno) ||
+         IsSystemVSharedMemory(sysno);
+#elif defined(__i386__) || defined(__mips__)
+  return IsSystemVIpc(sysno);
+#endif
+}
+
+bool SyscallSets::IsAdvancedScheduler(int sysno) {
+  switch (sysno) {
+    case __NR_ioprio_get:  // IO scheduler.
+    case __NR_ioprio_set:
+    case __NR_sched_get_priority_max:
+    case __NR_sched_get_priority_min:
+    case __NR_sched_getaffinity:
+    case __NR_sched_getattr:
+    case __NR_sched_getparam:
+    case __NR_sched_getscheduler:
+    case __NR_sched_rr_get_interval:
+    case __NR_sched_setaffinity:
+    case __NR_sched_setattr:
+    case __NR_sched_setparam:
+    case __NR_sched_setscheduler:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsInotify(int sysno) {
+  switch (sysno) {
+    case __NR_inotify_add_watch:
+#if !defined(__aarch64__)
+    case __NR_inotify_init:
+#endif
+    case __NR_inotify_init1:
+    case __NR_inotify_rm_watch:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsFaNotify(int sysno) {
+  switch (sysno) {
+    case __NR_fanotify_init:
+    case __NR_fanotify_mark:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsTimer(int sysno) {
+  switch (sysno) {
+    case __NR_getitimer:
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_alarm:
+#endif
+    case __NR_setitimer:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsAdvancedTimer(int sysno) {
+  switch (sysno) {
+    case __NR_timer_create:
+    case __NR_timer_delete:
+    case __NR_timer_getoverrun:
+    case __NR_timer_gettime:
+    case __NR_timer_settime:
+    case __NR_timerfd_create:
+    case __NR_timerfd_gettime:
+    case __NR_timerfd_settime:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsExtendedAttributes(int sysno) {
+  switch (sysno) {
+    case __NR_fgetxattr:
+    case __NR_flistxattr:
+    case __NR_fremovexattr:
+    case __NR_fsetxattr:
+    case __NR_getxattr:
+    case __NR_lgetxattr:
+    case __NR_listxattr:
+    case __NR_llistxattr:
+    case __NR_lremovexattr:
+    case __NR_lsetxattr:
+    case __NR_removexattr:
+    case __NR_setxattr:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Various system calls that need to be researched.
+// TODO(jln): classify this better.
+bool SyscallSets::IsMisc(int sysno) {
+  switch (sysno) {
+#if !defined(__mips__)
+    case __NR_getrandom:
+#endif
+    case __NR_name_to_handle_at:
+    case __NR_open_by_handle_at:
+    case __NR_perf_event_open:
+    case __NR_syncfs:
+    case __NR_vhangup:
+// The system calls below are not implemented.
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_afs_syscall:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_break:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_getpmsg:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_gtty:
+    case __NR_idle:
+    case __NR_lock:
+    case __NR_mpx:
+    case __NR_prof:
+    case __NR_profil:
+#endif
+#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+    case __NR_putpmsg:
+#endif
+#if defined(__x86_64__)
+    case __NR_security:
+#endif
+#if defined(__i386__) || defined(__mips__)
+    case __NR_stty:
+#endif
+#if defined(__x86_64__)
+    case __NR_tuxcall:
+#endif
+#if !defined(__aarch64__)
+    case __NR_vserver:
+#endif
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if defined(__arm__)
+bool SyscallSets::IsArmPciConfig(int sysno) {
+  switch (sysno) {
+    case __NR_pciconfig_iobase:
+    case __NR_pciconfig_read:
+    case __NR_pciconfig_write:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsArmPrivate(int sysno) {
+  switch (sysno) {
+    case __ARM_NR_breakpoint:
+    case __ARM_NR_cacheflush:
+    case __ARM_NR_set_tls:
+    case __ARM_NR_usr26:
+    case __ARM_NR_usr32:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif  // defined(__arm__)
+
+#if defined(__mips__)
+bool SyscallSets::IsMipsPrivate(int sysno) {
+  switch (sysno) {
+    case __NR_cacheflush:
+    case __NR_cachectl:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool SyscallSets::IsMipsMisc(int sysno) {
+  switch (sysno) {
+    case __NR_sysmips:
+    case __NR_unused150:
+      return true;
+    default:
+      return false;
+  }
+}
+#endif  // defined(__mips__)
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
new file mode 100644
index 0000000..5ba6335
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf-helpers/syscall_sets.h
@@ -0,0 +1,112 @@
+// 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 SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_SETS_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_SETS_H_
+
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/sandbox_export.h"
+
+// These are helpers to build seccomp-bpf policies, i.e. policies for a
+// sandbox that reduces the Linux kernel's attack surface. Given their
+// nature, they don't have any clear semantics and are completely
+// "implementation-defined".
+
+namespace sandbox {
+
+class SANDBOX_EXPORT SyscallSets {
+ public:
+  static bool IsKill(int sysno);
+  static bool IsAllowedGettime(int sysno);
+  static bool IsCurrentDirectory(int sysno);
+  static bool IsUmask(int sysno);
+  // System calls that directly access the file system. They might acquire
+  // a new file descriptor or otherwise perform an operation directly
+  // via a path.
+  static bool IsFileSystem(int sysno);
+  static bool IsAllowedFileSystemAccessViaFd(int sysno);
+  static bool IsDeniedFileSystemAccessViaFd(int sysno);
+  static bool IsGetSimpleId(int sysno);
+  static bool IsProcessPrivilegeChange(int sysno);
+  static bool IsProcessGroupOrSession(int sysno);
+  static bool IsAllowedSignalHandling(int sysno);
+  static bool IsAllowedOperationOnFd(int sysno);
+  static bool IsKernelInternalApi(int sysno);
+  // This should be thought through in conjunction with IsFutex().
+  static bool IsAllowedProcessStartOrDeath(int sysno);
+  // It's difficult to restrict those, but there is attack surface here.
+  static bool IsAllowedFutex(int sysno);
+  static bool IsAllowedEpoll(int sysno);
+  static bool IsAllowedGetOrModifySocket(int sysno);
+  static bool IsDeniedGetOrModifySocket(int sysno);
+
+#if defined(__i386__) || defined(__mips__)
+  // Big multiplexing system call for sockets.
+  static bool IsSocketCall(int sysno);
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__mips__) || \
+    defined(__aarch64__)
+  static bool IsNetworkSocketInformation(int sysno);
+#endif
+
+  static bool IsAllowedAddressSpaceAccess(int sysno);
+  static bool IsAllowedGeneralIo(int sysno);
+  static bool IsPrctl(int sysno);
+  static bool IsSeccomp(int sysno);
+  static bool IsAllowedBasicScheduler(int sysno);
+  static bool IsAdminOperation(int sysno);
+  static bool IsKernelModule(int sysno);
+  static bool IsGlobalFSViewChange(int sysno);
+  static bool IsFsControl(int sysno);
+  static bool IsNuma(int sysno);
+  static bool IsMessageQueue(int sysno);
+  static bool IsGlobalProcessEnvironment(int sysno);
+  static bool IsDebug(int sysno);
+  static bool IsGlobalSystemStatus(int sysno);
+  static bool IsEventFd(int sysno);
+  // Asynchronous I/O API.
+  static bool IsAsyncIo(int sysno);
+  static bool IsKeyManagement(int sysno);
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  static bool IsSystemVSemaphores(int sysno);
+#endif
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  // These give a lot of ambient authority and bypass the setuid sandbox.
+  static bool IsSystemVSharedMemory(int sysno);
+#endif
+
+#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
+  static bool IsSystemVMessageQueue(int sysno);
+#endif
+
+#if defined(__i386__) || defined(__mips__)
+  // Big system V multiplexing system call.
+  static bool IsSystemVIpc(int sysno);
+#endif
+
+  static bool IsAnySystemV(int sysno);
+  static bool IsAdvancedScheduler(int sysno);
+  static bool IsInotify(int sysno);
+  static bool IsFaNotify(int sysno);
+  static bool IsTimer(int sysno);
+  static bool IsAdvancedTimer(int sysno);
+  static bool IsExtendedAttributes(int sysno);
+  static bool IsMisc(int sysno);
+#if defined(__arm__)
+  static bool IsArmPciConfig(int sysno);
+  static bool IsArmPrivate(int sysno);
+#endif  // defined(__arm__)
+#if defined(__mips__)
+  static bool IsMipsPrivate(int sysno);
+  static bool IsMipsMisc(int sysno);
+#endif  // defined(__mips__)
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SyscallSets);
+};
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_SETS_H_
diff --git a/libchrome/sandbox/linux/seccomp-bpf/DEPS b/libchrome/sandbox/linux/seccomp-bpf/DEPS
new file mode 100644
index 0000000..149c463
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+sandbox/linux/bpf_dsl",
+  "+sandbox/linux/services",
+  "+sandbox/linux/system_headers",
+]
diff --git a/libchrome/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h b/libchrome/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
new file mode 100644
index 0000000..a4315ba
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.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 SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h"
+
+namespace sandbox {
+
+// This templated class allows building a BPFTesterDelegate from a
+// deprecated-style BPF policy (that is a SyscallEvaluator function pointer,
+// instead of a SandboxBPFPolicy class), specified in |policy_function| and a
+// function pointer to a test in |test_function|.
+// This allows both the policy and the test function to take a pointer to an
+// object of type "Aux" as a parameter. This is used to implement the BPF_TEST
+// macro and should generally not be used directly.
+template <class Policy, class Aux>
+class BPFTesterCompatibilityDelegate : public BPFTesterDelegate {
+ public:
+  typedef void (*TestFunction)(Aux*);
+
+  explicit BPFTesterCompatibilityDelegate(TestFunction test_function)
+      : aux_(), test_function_(test_function) {}
+
+  ~BPFTesterCompatibilityDelegate() override {}
+
+  std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+    // The current method is guaranteed to only run in the child process
+    // running the test. In this process, the current object is guaranteed
+    // to live forever. So it's ok to pass aux_pointer_for_policy_ to
+    // the policy, which could in turn pass it to the kernel via Trap().
+    return std::unique_ptr<bpf_dsl::Policy>(new Policy(&aux_));
+  }
+
+  void RunTestFunction() override {
+    // Run the actual test.
+    // The current object is guaranteed to live forever in the child process
+    // where this will run.
+    test_function_(&aux_);
+  }
+
+ private:
+  Aux aux_;
+  TestFunction test_function_;
+
+  DISALLOW_COPY_AND_ASSIGN(BPFTesterCompatibilityDelegate);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
diff --git a/libchrome/sandbox/linux/seccomp-bpf/bpf_tests.h b/libchrome/sandbox/linux/seccomp-bpf/bpf_tests.h
new file mode 100644
index 0000000..8b2b12a
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/bpf_tests.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 SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+// BPF_TEST_C() is a special version of SANDBOX_TEST(). It runs a test function
+// in a sub-process, under a seccomp-bpf policy specified in
+// |bpf_policy_class_name| without failing on configurations that are allowed
+// to not support seccomp-bpf in their kernels.
+// This is the preferred format for new BPF tests. |bpf_policy_class_name| is a
+// class name  (which will be default-constructed) that implements the
+// Policy interface.
+// The test function's body can simply follow. Test functions should use
+// the BPF_ASSERT macros defined below, not GTEST's macros. The use of
+// CHECK* macros is supported but less robust.
+#define BPF_TEST_C(test_case_name, test_name, bpf_policy_class_name)     \
+  BPF_DEATH_TEST_C(                                                      \
+      test_case_name, test_name, DEATH_SUCCESS(), bpf_policy_class_name)
+
+// Identical to BPF_TEST_C but allows to specify the nature of death.
+#define BPF_DEATH_TEST_C(                                            \
+    test_case_name, test_name, death, bpf_policy_class_name)         \
+  void BPF_TEST_C_##test_name();                                     \
+  TEST(test_case_name, DISABLE_ON_TSAN(test_name)) {                 \
+    sandbox::SandboxBPFTestRunner bpf_test_runner(                   \
+        new sandbox::BPFTesterSimpleDelegate<bpf_policy_class_name>( \
+            BPF_TEST_C_##test_name));                                \
+    sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death);   \
+  }                                                                  \
+  void BPF_TEST_C_##test_name()
+
+// This form of BPF_TEST is a little verbose and should be reserved for complex
+// tests where a lot of control is required.
+// |bpf_tester_delegate_class| must be a classname implementing the
+// BPFTesterDelegate interface.
+#define BPF_TEST_D(test_case_name, test_name, bpf_tester_delegate_class)     \
+  BPF_DEATH_TEST_D(                                                          \
+      test_case_name, test_name, DEATH_SUCCESS(), bpf_tester_delegate_class)
+
+// Identical to BPF_TEST_D but allows to specify the nature of death.
+#define BPF_DEATH_TEST_D(                                          \
+    test_case_name, test_name, death, bpf_tester_delegate_class)   \
+  TEST(test_case_name, DISABLE_ON_TSAN(test_name)) {               \
+    sandbox::SandboxBPFTestRunner bpf_test_runner(                 \
+        new bpf_tester_delegate_class());                          \
+    sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
+  }
+
+// Assertions are handled exactly the same as with a normal SANDBOX_TEST()
+#define BPF_ASSERT SANDBOX_ASSERT
+#define BPF_ASSERT_EQ(x, y) BPF_ASSERT((x) == (y))
+#define BPF_ASSERT_NE(x, y) BPF_ASSERT((x) != (y))
+#define BPF_ASSERT_LT(x, y) BPF_ASSERT((x) < (y))
+#define BPF_ASSERT_GT(x, y) BPF_ASSERT((x) > (y))
+#define BPF_ASSERT_LE(x, y) BPF_ASSERT((x) <= (y))
+#define BPF_ASSERT_GE(x, y) BPF_ASSERT((x) >= (y))
+
+// This form of BPF_TEST is now discouraged (but still allowed) in favor of
+// BPF_TEST_D and BPF_TEST_C.
+// The |policy| parameter should be a Policy subclass.
+// BPF_TEST() takes a C++ data type as an fourth parameter. A variable
+// of this type will be allocated and a pointer to it will be
+// available within the test function as "BPF_AUX". The pointer will
+// also be passed as an argument to the policy's constructor. Policies
+// would typically use it as an argument to SandboxBPF::Trap(), if
+// they want to communicate data between the BPF_TEST() and a Trap()
+// function. The life-time of this object is the same as the life-time
+// of the process running under the seccomp-bpf policy.
+// |aux| must not be void.
+#define BPF_TEST(test_case_name, test_name, policy, aux) \
+  BPF_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS(), policy, aux)
+
+// A BPF_DEATH_TEST is just the same as a BPF_TEST, but it assumes that the
+// test will fail with a particular known error condition. Use the DEATH_XXX()
+// macros from unit_tests.h to specify the expected error condition.
+#define BPF_DEATH_TEST(test_case_name, test_name, death, policy, aux) \
+  void BPF_TEST_##test_name(aux* BPF_AUX);                            \
+  TEST(test_case_name, DISABLE_ON_TSAN(test_name)) {                  \
+    sandbox::SandboxBPFTestRunner bpf_test_runner(                    \
+        new sandbox::BPFTesterCompatibilityDelegate<policy, aux>(     \
+            BPF_TEST_##test_name));                                   \
+    sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death);    \
+  }                                                                   \
+  void BPF_TEST_##test_name(aux* BPF_AUX)
+
+// This class takes a simple function pointer as a constructor parameter and a
+// class name as a template parameter to implement the BPFTesterDelegate
+// interface which can be used to build BPF unittests with
+// the SandboxBPFTestRunner class.
+template <class PolicyClass>
+class BPFTesterSimpleDelegate : public BPFTesterDelegate {
+ public:
+  explicit BPFTesterSimpleDelegate(void (*test_function)(void))
+      : test_function_(test_function) {}
+  ~BPFTesterSimpleDelegate() override {}
+
+  std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+    return std::unique_ptr<bpf_dsl::Policy>(new PolicyClass());
+  }
+  void RunTestFunction() override {
+    DCHECK(test_function_);
+    test_function_();
+  }
+
+ private:
+  void (*test_function_)(void);
+  DISALLOW_COPY_AND_ASSIGN(BPFTesterSimpleDelegate);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
diff --git a/libchrome/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc b/libchrome/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
new file mode 100644
index 0000000..c16cd72
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
@@ -0,0 +1,155 @@
+// 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 "sandbox/linux/seccomp-bpf/bpf_tests.h"
+
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::ResultExpr;
+
+namespace sandbox {
+
+namespace {
+
+class FourtyTwo {
+ public:
+  static const int kMagicValue = 42;
+  FourtyTwo() : value_(kMagicValue) {}
+  int value() { return value_; }
+
+ private:
+  int value_;
+  DISALLOW_COPY_AND_ASSIGN(FourtyTwo);
+};
+
+class EmptyClassTakingPolicy : public bpf_dsl::Policy {
+ public:
+  explicit EmptyClassTakingPolicy(FourtyTwo* fourty_two) {
+    BPF_ASSERT(fourty_two);
+    BPF_ASSERT(FourtyTwo::kMagicValue == fourty_two->value());
+  }
+  ~EmptyClassTakingPolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    return Allow();
+  }
+};
+
+BPF_TEST(BPFTest,
+         BPFAUXPointsToClass,
+         EmptyClassTakingPolicy,
+         FourtyTwo /* *BPF_AUX */) {
+  // BPF_AUX should point to an instance of FourtyTwo.
+  BPF_ASSERT(BPF_AUX);
+  BPF_ASSERT(FourtyTwo::kMagicValue == BPF_AUX->value());
+}
+
+void DummyTestFunction(FourtyTwo *fourty_two) {
+}
+
+TEST(BPFTest, BPFTesterCompatibilityDelegateLeakTest) {
+  // Don't do anything, simply gives dynamic tools an opportunity to detect
+  // leaks.
+  {
+    BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>
+        simple_delegate(DummyTestFunction);
+  }
+  {
+    // Test polymorphism.
+    std::unique_ptr<BPFTesterDelegate> simple_delegate(
+        new BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>(
+            DummyTestFunction));
+  }
+}
+
+class EnosysPtracePolicy : public bpf_dsl::Policy {
+ public:
+  EnosysPtracePolicy() { my_pid_ = sys_getpid(); }
+  ~EnosysPtracePolicy() override {
+    // Policies should be able to bind with the process on which they are
+    // created. They should never be created in a parent process.
+    BPF_ASSERT_EQ(my_pid_, sys_getpid());
+  }
+
+  ResultExpr EvaluateSyscall(int system_call_number) const override {
+    CHECK(SandboxBPF::IsValidSyscallNumber(system_call_number));
+    if (system_call_number == __NR_ptrace) {
+      // The EvaluateSyscall function should run in the process that created
+      // the current object.
+      BPF_ASSERT_EQ(my_pid_, sys_getpid());
+      return Error(ENOSYS);
+    } else {
+      return Allow();
+    }
+  }
+
+ private:
+  pid_t my_pid_;
+  DISALLOW_COPY_AND_ASSIGN(EnosysPtracePolicy);
+};
+
+class BasicBPFTesterDelegate : public BPFTesterDelegate {
+ public:
+  BasicBPFTesterDelegate() {}
+  ~BasicBPFTesterDelegate() override {}
+
+  std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+    return std::unique_ptr<bpf_dsl::Policy>(new EnosysPtracePolicy());
+  }
+  void RunTestFunction() override {
+    errno = 0;
+    int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
+    BPF_ASSERT(-1 == ret);
+    BPF_ASSERT(ENOSYS == errno);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicBPFTesterDelegate);
+};
+
+// This is the most powerful and complex way to create a BPF test, but it
+// requires a full class definition (BasicBPFTesterDelegate).
+BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, BasicBPFTesterDelegate);
+
+// This is the simplest form of BPF tests.
+BPF_TEST_C(BPFTest, BPFTestWithInlineTest, EnosysPtracePolicy) {
+  errno = 0;
+  int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
+  BPF_ASSERT(-1 == ret);
+  BPF_ASSERT(ENOSYS == errno);
+}
+
+const char kHelloMessage[] = "Hello";
+
+BPF_DEATH_TEST_C(BPFTest,
+                 BPFDeathTestWithInlineTest,
+                 DEATH_MESSAGE(kHelloMessage),
+                 EnosysPtracePolicy) {
+  LOG(ERROR) << kHelloMessage;
+  _exit(1);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf/die.cc b/libchrome/sandbox/linux/seccomp-bpf/die.cc
new file mode 100644
index 0000000..3baf1f1
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/die.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 "sandbox/linux/seccomp-bpf/die.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace sandbox {
+
+void Die::ExitGroup() {
+  // exit_group() should exit our program. After all, it is defined as a
+  // function that doesn't return. But things can theoretically go wrong.
+  // Especially, since we are dealing with system call filters. Continuing
+  // execution would be very bad in most cases where ExitGroup() gets called.
+  // So, we'll try a few other strategies too.
+  Syscall::Call(__NR_exit_group, 1);
+
+  // We have no idea what our run-time environment looks like. So, signal
+  // handlers might or might not do the right thing. Try to reset settings
+  // to a defined state; but we have not way to verify whether we actually
+  // succeeded in doing so. Nonetheless, triggering a fatal signal could help
+  // us terminate.
+  struct sigaction sa = {};
+  sa.sa_handler = LINUX_SIG_DFL;
+  sa.sa_flags = LINUX_SA_RESTART;
+  sys_sigaction(LINUX_SIGSEGV, &sa, nullptr);
+  Syscall::Call(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0);
+  if (*(volatile char*)0) {
+  }
+
+  // If there is no way for us to ask for the program to exit, the next
+  // best thing we can do is to loop indefinitely. Maybe, somebody will notice
+  // and file a bug...
+  // We in fact retry the system call inside of our loop so that it will
+  // stand out when somebody tries to diagnose the problem by using "strace".
+  for (;;) {
+    Syscall::Call(__NR_exit_group, 1);
+  }
+}
+
+void Die::SandboxDie(const char* msg, const char* file, int line) {
+  if (simple_exit_) {
+    LogToStderr(msg, file, line);
+  } else {
+    logging::LogMessage(file, line, logging::LOG_FATAL).stream() << msg;
+  }
+  ExitGroup();
+}
+
+void Die::RawSandboxDie(const char* msg) {
+  if (!msg)
+    msg = "";
+  RAW_LOG(FATAL, msg);
+  ExitGroup();
+}
+
+void Die::SandboxInfo(const char* msg, const char* file, int line) {
+  if (!suppress_info_) {
+    logging::LogMessage(file, line, logging::LOG_INFO).stream() << msg;
+  }
+}
+
+void Die::LogToStderr(const char* msg, const char* file, int line) {
+  if (msg) {
+    char buf[40];
+    snprintf(buf, sizeof(buf), "%d", line);
+    std::string s = std::string(file) + ":" + buf + ":" + msg + "\n";
+
+    // No need to loop. Short write()s are unlikely and if they happen we
+    // probably prefer them over a loop that blocks.
+    ignore_result(
+        HANDLE_EINTR(Syscall::Call(__NR_write, 2, s.c_str(), s.length())));
+  }
+}
+
+bool Die::simple_exit_ = false;
+bool Die::suppress_info_ = false;
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf/die.h b/libchrome/sandbox/linux/seccomp-bpf/die.h
new file mode 100644
index 0000000..b3f3f72
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/die.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 SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This is the main API for using this file. Prints a error message and
+// exits with a fatal error. This is not async-signal safe.
+#define SANDBOX_DIE(m) sandbox::Die::SandboxDie(m, __FILE__, __LINE__)
+
+// An async signal safe version of the same API. Won't print the filename
+// and line numbers.
+#define RAW_SANDBOX_DIE(m) sandbox::Die::RawSandboxDie(m)
+
+// Adds an informational message to the log file or stderr as appropriate.
+#define SANDBOX_INFO(m) sandbox::Die::SandboxInfo(m, __FILE__, __LINE__)
+
+class SANDBOX_EXPORT Die {
+ public:
+  // Terminate the program, even if the current sandbox policy prevents some
+  // of the more commonly used functions used for exiting.
+  // Most users would want to call SANDBOX_DIE() instead, as it logs extra
+  // information. But calling ExitGroup() is correct and in some rare cases
+  // preferable. So, we make it part of the public API.
+  static void ExitGroup() __attribute__((noreturn));
+
+  // This method gets called by SANDBOX_DIE(). There is normally no reason
+  // to call it directly unless you are defining your own exiting macro.
+  static void SandboxDie(const char* msg, const char* file, int line)
+      __attribute__((noreturn));
+
+  static void RawSandboxDie(const char* msg) __attribute__((noreturn));
+
+  // This method gets called by SANDBOX_INFO(). There is normally no reason
+  // to call it directly unless you are defining your own logging macro.
+  static void SandboxInfo(const char* msg, const char* file, int line);
+
+  // Writes a message to stderr. Used as a fall-back choice, if we don't have
+  // any other way to report an error.
+  static void LogToStderr(const char* msg, const char* file, int line);
+
+  // We generally want to run all exit handlers. This means, on SANDBOX_DIE()
+  // we should be calling LOG(FATAL). But there are some situations where
+  // we just need to print a message and then terminate. This would typically
+  // happen in cases where we consume the error message internally (e.g. in
+  // unit tests or in the supportsSeccompSandbox() method).
+  static void EnableSimpleExit() { simple_exit_ = true; }
+
+  // Sometimes we need to disable all informational messages (e.g. from within
+  // unittests).
+  static void SuppressInfoMessages(bool flag) { suppress_info_ = flag; }
+
+ private:
+  static bool simple_exit_;
+  static bool suppress_info_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Die);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
diff --git a/libchrome/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/libchrome/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
new file mode 100644
index 0000000..4d8d436
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -0,0 +1,279 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+namespace {
+
+bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
+
+bool IsSingleThreaded(int proc_fd) {
+  return ThreadHelpers::IsSingleThreaded(proc_fd);
+}
+
+// Check if the kernel supports seccomp-filter (a.k.a. seccomp mode 2) via
+// prctl().
+bool KernelSupportsSeccompBPF() {
+  errno = 0;
+  const int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
+
+  if (rv == -1 && EFAULT == errno) {
+    return true;
+  }
+  return false;
+}
+
+// LG introduced a buggy syscall, sys_set_media_ext, with the same number as
+// seccomp. Return true if the current kernel has this buggy syscall.
+//
+// We want this to work with upcoming versions of seccomp, so we pass bogus
+// flags that are unlikely to ever be used by the kernel. A normal kernel would
+// return -EINVAL, but a buggy LG kernel would return 1.
+bool KernelHasLGBug() {
+#if defined(OS_ANDROID)
+  // sys_set_media will see this as NULL, which should be a safe (non-crashing)
+  // way to invoke it. A genuine seccomp syscall will see it as
+  // SECCOMP_SET_MODE_STRICT.
+  const unsigned int operation = 0;
+  // Chosen by fair dice roll. Guaranteed to be random.
+  const unsigned int flags = 0xf7a46a5c;
+  const int rv = sys_seccomp(operation, flags, nullptr);
+  // A genuine kernel would return -EINVAL (which would set rv to -1 and errno
+  // to EINVAL), or at the very least return some kind of error (which would
+  // set rv to -1). Any other behavior indicates that whatever code received
+  // our syscall was not the real seccomp.
+  if (rv != -1) {
+    return true;
+  }
+#endif  // defined(OS_ANDROID)
+
+  return false;
+}
+
+// Check if the kernel supports seccomp-filter via the seccomp system call
+// and the TSYNC feature to enable seccomp on all threads.
+bool KernelSupportsSeccompTsync() {
+  if (KernelHasLGBug()) {
+    return false;
+  }
+
+  errno = 0;
+  const int rv =
+      sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr);
+
+  if (rv == -1 && errno == EFAULT) {
+    return true;
+  } else {
+    // TODO(jln): turn these into DCHECK after 417888 is considered fixed.
+    CHECK_EQ(-1, rv);
+    CHECK(ENOSYS == errno || EINVAL == errno);
+    return false;
+  }
+}
+
+uint64_t EscapePC() {
+  intptr_t rv = Syscall::Call(-1);
+  if (rv == -1 && errno == ENOSYS) {
+    return 0;
+  }
+  return static_cast<uint64_t>(static_cast<uintptr_t>(rv));
+}
+
+intptr_t SandboxPanicTrap(const struct arch_seccomp_data&, void* aux) {
+  SANDBOX_DIE(static_cast<const char*>(aux));
+}
+
+bpf_dsl::ResultExpr SandboxPanic(const char* error) {
+  return bpf_dsl::Trap(SandboxPanicTrap, error);
+}
+
+}  // namespace
+
+SandboxBPF::SandboxBPF(bpf_dsl::Policy* policy)
+    : proc_fd_(), sandbox_has_started_(false), policy_(policy) {
+}
+
+SandboxBPF::~SandboxBPF() {
+}
+
+// static
+bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
+  // Never pretend to support seccomp with Valgrind, as it
+  // throws the tool off.
+  if (IsRunningOnValgrind()) {
+    return false;
+  }
+
+  switch (level) {
+    case SeccompLevel::SINGLE_THREADED:
+      return KernelSupportsSeccompBPF();
+    case SeccompLevel::MULTI_THREADED:
+      return KernelSupportsSeccompTsync();
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) {
+  DCHECK(policy_);
+  CHECK(seccomp_level == SeccompLevel::SINGLE_THREADED ||
+        seccomp_level == SeccompLevel::MULTI_THREADED);
+
+  if (sandbox_has_started_) {
+    SANDBOX_DIE(
+        "Cannot repeatedly start sandbox. Create a separate Sandbox "
+        "object instead.");
+    return false;
+  }
+
+  if (!proc_fd_.is_valid()) {
+    SetProcFd(ProcUtil::OpenProc());
+  }
+
+  const bool supports_tsync = KernelSupportsSeccompTsync();
+
+  if (seccomp_level == SeccompLevel::SINGLE_THREADED) {
+    // Wait for /proc/self/task/ to update if needed and assert the
+    // process is single threaded.
+    ThreadHelpers::AssertSingleThreaded(proc_fd_.get());
+  } else if (seccomp_level == SeccompLevel::MULTI_THREADED) {
+    if (IsSingleThreaded(proc_fd_.get())) {
+      SANDBOX_DIE("Cannot start sandbox; "
+                  "process may be single-threaded when reported as not");
+      return false;
+    }
+    if (!supports_tsync) {
+      SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
+                  "filters for a threadgroup");
+      return false;
+    }
+  }
+
+  // We no longer need access to any files in /proc. We want to do this
+  // before installing the filters, just in case that our policy denies
+  // close().
+  if (proc_fd_.is_valid()) {
+    proc_fd_.reset();
+  }
+
+  // Install the filters.
+  InstallFilter(supports_tsync ||
+                seccomp_level == SeccompLevel::MULTI_THREADED);
+
+  return true;
+}
+
+void SandboxBPF::SetProcFd(base::ScopedFD proc_fd) {
+  proc_fd_.swap(proc_fd);
+}
+
+// static
+bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
+  return SyscallSet::IsValid(sysnum);
+}
+
+// static
+bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
+  return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
+}
+
+// static
+intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
+  return Syscall::Call(
+      args.nr, static_cast<intptr_t>(args.args[0]),
+      static_cast<intptr_t>(args.args[1]), static_cast<intptr_t>(args.args[2]),
+      static_cast<intptr_t>(args.args[3]), static_cast<intptr_t>(args.args[4]),
+      static_cast<intptr_t>(args.args[5]));
+}
+
+CodeGen::Program SandboxBPF::AssembleFilter() {
+  DCHECK(policy_);
+
+  bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
+  if (Trap::SandboxDebuggingAllowedByUser()) {
+    compiler.DangerousSetEscapePC(EscapePC());
+  }
+  compiler.SetPanicFunc(SandboxPanic);
+  return compiler.Compile();
+}
+
+void SandboxBPF::InstallFilter(bool must_sync_threads) {
+  // We want to be very careful in not imposing any requirements on the
+  // policies that are set with SetSandboxPolicy(). This means, as soon as
+  // the sandbox is active, we shouldn't be relying on libraries that could
+  // be making system calls. This, for example, means we should avoid
+  // using the heap and we should avoid using STL functions.
+  // Temporarily copy the contents of the "program" vector into a
+  // stack-allocated array; and then explicitly destroy that object.
+  // This makes sure we don't ex- or implicitly call new/delete after we
+  // installed the BPF filter program in the kernel. Depending on the
+  // system memory allocator that is in effect, these operators can result
+  // in system calls to things like munmap() or brk().
+  CodeGen::Program program = AssembleFilter();
+
+  struct sock_filter bpf[program.size()];
+  const struct sock_fprog prog = {static_cast<unsigned short>(program.size()),
+                                  bpf};
+  memcpy(bpf, &program[0], sizeof(bpf));
+  CodeGen::Program().swap(program);  // vector swap trick
+
+  // Make an attempt to release memory that is no longer needed here, rather
+  // than in the destructor. Try to avoid as much as possible to presume of
+  // what will be possible to do in the new (sandboxed) execution environment.
+  policy_.reset();
+
+  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+    SANDBOX_DIE("Kernel refuses to enable no-new-privs");
+  }
+
+  // Install BPF filter program. If the thread state indicates multi-threading
+  // support, then the kernel hass the seccomp system call. Otherwise, fall
+  // back on prctl, which requires the process to be single-threaded.
+  if (must_sync_threads) {
+    int rv =
+        sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
+    if (rv) {
+      SANDBOX_DIE(
+          "Kernel refuses to turn on and synchronize threads for BPF filters");
+    }
+  } else {
+    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
+      SANDBOX_DIE("Kernel refuses to turn on BPF filters");
+    }
+  }
+
+  sandbox_has_started_ = true;
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/libchrome/sandbox/linux/seccomp-bpf/sandbox_bpf.h
new file mode 100644
index 0000000..1637b26
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/sandbox_bpf.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+struct arch_seccomp_data;
+namespace bpf_dsl {
+class Policy;
+}
+
+// This class can be used to apply a syscall sandboxing policy expressed in a
+// bpf_dsl::Policy object to the current process.
+// Syscall sandboxing policies get inherited by subprocesses and, once applied,
+// can never be removed for the lifetime of the process.
+class SANDBOX_EXPORT SandboxBPF {
+ public:
+  enum class SeccompLevel {
+    SINGLE_THREADED,
+    MULTI_THREADED,
+  };
+
+  // Ownership of |policy| is transfered here to the sandbox object.
+  // nullptr is allowed for unit tests.
+  explicit SandboxBPF(bpf_dsl::Policy* policy);
+  // NOTE: Setting a policy and starting the sandbox is a one-way operation.
+  // The kernel does not provide any option for unloading a loaded sandbox. The
+  // sandbox remains engaged even when the object is destructed.
+  ~SandboxBPF();
+
+  // Detect if the kernel supports the specified seccomp level.
+  // See StartSandbox() for a description of these.
+  static bool SupportsSeccompSandbox(SeccompLevel level);
+
+  // This is the main public entry point. It sets up the resources needed by
+  // the sandbox, and enters Seccomp mode.
+  // The calling process must provide a |level| to tell the sandbox which type
+  // of kernel support it should engage.
+  // SINGLE_THREADED will only sandbox the calling thread. Since it would be a
+  // security risk, the sandbox will also check that the current process is
+  // single threaded and crash if it isn't the case.
+  // MULTI_THREADED requires more recent kernel support and allows to sandbox
+  // all the threads of the current process. Be mindful of potential races,
+  // with other threads using disallowed system calls either before or after
+  // the sandbox is engaged.
+  //
+  // It is possible to stack multiple sandboxes by creating separate "Sandbox"
+  // objects and calling "StartSandbox()" on each of them. Please note, that
+  // this requires special care, though, as newly stacked sandboxes can never
+  // relax restrictions imposed by earlier sandboxes. Furthermore, installing
+  // a new policy requires making system calls, that might already be
+  // disallowed.
+  // Finally, stacking does add more kernel overhead than having a single
+  // combined policy. So, it should only be used if there are no alternatives.
+  bool StartSandbox(SeccompLevel level) WARN_UNUSED_RESULT;
+
+  // The sandbox needs to be able to access files in "/proc/self/". If
+  // this directory is not accessible when "StartSandbox()" gets called, the
+  // caller must provide an already opened file descriptor by calling
+  // "SetProcFd()".
+  // The sandbox becomes the new owner of this file descriptor and will
+  // close it when "StartSandbox()" executes or when the sandbox object
+  // disappears.
+  void SetProcFd(base::ScopedFD proc_fd);
+
+  // Checks whether a particular system call number is valid on the current
+  // architecture.
+  static bool IsValidSyscallNumber(int sysnum);
+
+  // UnsafeTraps require some syscalls to always be allowed.
+  // This helper function returns true for these calls.
+  static bool IsRequiredForUnsafeTrap(int sysno);
+
+  // From within an UnsafeTrap() it is often useful to be able to execute
+  // the system call that triggered the trap. The ForwardSyscall() method
+  // makes this easy. It is more efficient than calling glibc's syscall()
+  // function, as it avoid the extra round-trip to the signal handler. And
+  // it automatically does the correct thing to report kernel-style error
+  // conditions, rather than setting errno. See the comments for TrapFnc for
+  // details. In other words, the return value from ForwardSyscall() is
+  // directly suitable as a return value for a trap handler.
+  static intptr_t ForwardSyscall(const struct arch_seccomp_data& args);
+
+ private:
+  friend class SandboxBPFTestRunner;
+
+  // Assembles a BPF filter program from the current policy. After calling this
+  // function, you must not call any other sandboxing function.
+  CodeGen::Program AssembleFilter();
+
+  // Assembles and installs a filter based on the policy that has previously
+  // been configured with SetSandboxPolicy().
+  void InstallFilter(bool must_sync_threads);
+
+  base::ScopedFD proc_fd_;
+  bool sandbox_has_started_;
+  std::unique_ptr<bpf_dsl::Policy> policy_;
+
+  DISALLOW_COPY_AND_ASSIGN(SandboxBPF);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
diff --git a/libchrome/sandbox/linux/seccomp-bpf/syscall.cc b/libchrome/sandbox/linux/seccomp-bpf/syscall.cc
new file mode 100644
index 0000000..4d55936
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/syscall.cc
@@ -0,0 +1,433 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+
+#include <errno.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+
+namespace sandbox {
+
+namespace {
+
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS_FAMILY)
+// Number that's not currently used by any Linux kernel ABIs.
+const int kInvalidSyscallNumber = 0x351d3;
+#else
+#error Unrecognized architecture
+#endif
+
+asm(// We need to be able to tell the kernel exactly where we made a
+    // system call. The C++ compiler likes to sometimes clone or
+    // inline code, which would inadvertently end up duplicating
+    // the entry point.
+    // "gcc" can suppress code duplication with suitable function
+    // attributes, but "clang" doesn't have this ability.
+    // The "clang" developer mailing list suggested that the correct
+    // and portable solution is a file-scope assembly block.
+    // N.B. We do mark our code as a proper function so that backtraces
+    // work correctly. But we make absolutely no attempt to use the
+    // ABI's calling conventions for passing arguments. We will only
+    // ever be called from assembly code and thus can pick more
+    // suitable calling conventions.
+#if defined(__i386__)
+    ".text\n"
+    ".align 16, 0x90\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.cfi_startproc\n"
+    // Check if "%eax" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "int $0x80". This address can be
+    // used as a marker that BPF code inspects.
+    "test %eax, %eax\n"
+    "jge  1f\n"
+    // Always, make sure that our code is position-independent, or
+    // address space randomization might not work on i386. This means,
+    // we can't use "lea", but instead have to rely on "call/pop".
+    "call 0f;   .cfi_adjust_cfa_offset  4\n"
+    "0:pop  %eax; .cfi_adjust_cfa_offset -4\n"
+    "addl $2f-0b, %eax\n"
+    "ret\n"
+    // Save register that we don't want to clobber. On i386, we need to
+    // save relatively aggressively, as there are a couple or registers
+    // that are used internally (e.g. %ebx for position-independent
+    // code, and %ebp for the frame pointer), and as we need to keep at
+    // least a few registers available for the register allocator.
+    "1:push %esi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset esi, 0\n"
+    "push %edi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset edi, 0\n"
+    "push %ebx; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebx, 0\n"
+    "push %ebp; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebp, 0\n"
+    // Copy entries from the array holding the arguments into the
+    // correct CPU registers.
+    "movl  0(%edi), %ebx\n"
+    "movl  4(%edi), %ecx\n"
+    "movl  8(%edi), %edx\n"
+    "movl 12(%edi), %esi\n"
+    "movl 20(%edi), %ebp\n"
+    "movl 16(%edi), %edi\n"
+    // Enter the kernel.
+    "int  $0x80\n"
+    // This is our "magic" return address that the BPF filter sees.
+    "2:"
+    // Restore any clobbered registers that we didn't declare to the
+    // compiler.
+    "pop  %ebp; .cfi_restore ebp; .cfi_adjust_cfa_offset -4\n"
+    "pop  %ebx; .cfi_restore ebx; .cfi_adjust_cfa_offset -4\n"
+    "pop  %edi; .cfi_restore edi; .cfi_adjust_cfa_offset -4\n"
+    "pop  %esi; .cfi_restore esi; .cfi_adjust_cfa_offset -4\n"
+    "ret\n"
+    ".cfi_endproc\n"
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__x86_64__)
+    ".text\n"
+    ".align 16, 0x90\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.cfi_startproc\n"
+    // Check if "%rdi" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "syscall". This address can be
+    // used as a marker that BPF code inspects.
+    "test %rdi, %rdi\n"
+    "jge  1f\n"
+    // Always make sure that our code is position-independent, or the
+    // linker will throw a hissy fit on x86-64.
+    "lea 2f(%rip), %rax\n"
+    "ret\n"
+    // Now we load the registers used to pass arguments to the system
+    // call: system call number in %rax, and arguments in %rdi, %rsi,
+    // %rdx, %r10, %r8, %r9. Note: These are all caller-save registers
+    // (only %rbx, %rbp, %rsp, and %r12-%r15 are callee-save), so no
+    // need to worry here about spilling registers or CFI directives.
+    "1:movq %rdi, %rax\n"
+    "movq  0(%rsi), %rdi\n"
+    "movq 16(%rsi), %rdx\n"
+    "movq 24(%rsi), %r10\n"
+    "movq 32(%rsi), %r8\n"
+    "movq 40(%rsi), %r9\n"
+    "movq  8(%rsi), %rsi\n"
+    // Enter the kernel.
+    "syscall\n"
+    // This is our "magic" return address that the BPF filter sees.
+    "2:ret\n"
+    ".cfi_endproc\n"
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__arm__)
+    // Throughout this file, we use the same mode (ARM vs. thumb)
+    // that the C++ compiler uses. This means, when transfering control
+    // from C++ to assembly code, we do not need to switch modes (e.g.
+    // by using the "bx" instruction). It also means that our assembly
+    // code should not be invoked directly from code that lives in
+    // other compilation units, as we don't bother implementing thumb
+    // interworking. That's OK, as we don't make any of the assembly
+    // symbols public. They are all local to this file.
+    ".text\n"
+    ".align 2\n"
+    ".type SyscallAsm, %function\n"
+#if defined(__thumb__)
+    ".thumb_func\n"
+#else
+    ".arm\n"
+#endif
+    "SyscallAsm:\n"
+#if !defined(__native_client_nonsfi__)
+    // .fnstart and .fnend pseudo operations creates unwind table.
+    // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which
+    // is not provided by PNaCl toolchain. Disable it.
+    ".fnstart\n"
+#endif
+    "@ args = 0, pretend = 0, frame = 8\n"
+    "@ frame_needed = 1, uses_anonymous_args = 0\n"
+#if defined(__thumb__)
+    ".cfi_startproc\n"
+    "push {r7, lr}\n"
+    ".save {r7, lr}\n"
+    ".cfi_offset 14, -4\n"
+    ".cfi_offset  7, -8\n"
+    ".cfi_def_cfa_offset 8\n"
+#else
+    "stmfd sp!, {fp, lr}\n"
+    "add fp, sp, #4\n"
+#endif
+    // Check if "r0" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "swi 0". This address can be
+    // used as a marker that BPF code inspects.
+    "cmp r0, #0\n"
+    "bge 1f\n"
+    "adr r0, 2f\n"
+    "b   2f\n"
+    // We declared (almost) all clobbered registers to the compiler. On
+    // ARM there is no particular register pressure. So, we can go
+    // ahead and directly copy the entries from the arguments array
+    // into the appropriate CPU registers.
+    "1:ldr r5, [r6, #20]\n"
+    "ldr r4, [r6, #16]\n"
+    "ldr r3, [r6, #12]\n"
+    "ldr r2, [r6, #8]\n"
+    "ldr r1, [r6, #4]\n"
+    "mov r7, r0\n"
+    "ldr r0, [r6, #0]\n"
+    // Enter the kernel
+    "swi 0\n"
+// Restore the frame pointer. Also restore the program counter from
+// the link register; this makes us return to the caller.
+#if defined(__thumb__)
+    "2:pop {r7, pc}\n"
+    ".cfi_endproc\n"
+#else
+    "2:ldmfd sp!, {fp, pc}\n"
+#endif
+#if !defined(__native_client_nonsfi__)
+    // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment,
+    // for more details.
+    ".fnend\n"
+#endif
+    "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__mips__)
+    ".text\n"
+    ".option pic2\n"
+    ".align 4\n"
+    ".global SyscallAsm\n"
+    ".type SyscallAsm, @function\n"
+    "SyscallAsm:.ent SyscallAsm\n"
+    ".frame  $sp, 40, $ra\n"
+    ".set   push\n"
+    ".set   noreorder\n"
+    ".cpload $t9\n"
+    "addiu  $sp, $sp, -40\n"
+    "sw     $ra, 36($sp)\n"
+    // Check if "v0" is negative. If so, do not attempt to make a
+    // system call. Instead, compute the return address that is visible
+    // to the kernel after we execute "syscall". This address can be
+    // used as a marker that BPF code inspects.
+    "bgez   $v0, 1f\n"
+    " nop\n"
+    // This is equivalent to "la $v0, 2f".
+    // LA macro has to be avoided since LLVM-AS has issue with LA in PIC mode
+    // https://llvm.org/bugs/show_bug.cgi?id=27644
+    "lw     $v0, %got(2f)($gp)\n"
+    "addiu  $v0, $v0, %lo(2f)\n"
+    "b      2f\n"
+    " nop\n"
+    // On MIPS first four arguments go to registers a0 - a3 and any
+    // argument after that goes to stack. We can go ahead and directly
+    // copy the entries from the arguments array into the appropriate
+    // CPU registers and on the stack.
+    "1:lw     $a3, 28($a0)\n"
+    "lw     $a2, 24($a0)\n"
+    "lw     $a1, 20($a0)\n"
+    "lw     $t0, 16($a0)\n"
+    "sw     $a3, 28($sp)\n"
+    "sw     $a2, 24($sp)\n"
+    "sw     $a1, 20($sp)\n"
+    "sw     $t0, 16($sp)\n"
+    "lw     $a3, 12($a0)\n"
+    "lw     $a2, 8($a0)\n"
+    "lw     $a1, 4($a0)\n"
+    "lw     $a0, 0($a0)\n"
+    // Enter the kernel
+    "syscall\n"
+    // This is our "magic" return address that the BPF filter sees.
+    // Restore the return address from the stack.
+    "2:lw     $ra, 36($sp)\n"
+    "jr     $ra\n"
+    " addiu  $sp, $sp, 40\n"
+    ".set    pop\n"
+    ".end    SyscallAsm\n"
+    ".size   SyscallAsm,.-SyscallAsm\n"
+#elif defined(__aarch64__)
+    ".text\n"
+    ".align 2\n"
+    ".type SyscallAsm, %function\n"
+    "SyscallAsm:\n"
+    ".cfi_startproc\n"
+    "cmp x0, #0\n"
+    "b.ge 1f\n"
+    "adr x0,2f\n"
+    "b 2f\n"
+    "1:ldr x5, [x6, #40]\n"
+    "ldr x4, [x6, #32]\n"
+    "ldr x3, [x6, #24]\n"
+    "ldr x2, [x6, #16]\n"
+    "ldr x1, [x6, #8]\n"
+    "mov x8, x0\n"
+    "ldr x0, [x6, #0]\n"
+    // Enter the kernel
+    "svc 0\n"
+    "2:ret\n"
+    ".cfi_endproc\n"
+    ".size SyscallAsm, .-SyscallAsm\n"
+#endif
+    );  // asm
+
+#if defined(__x86_64__)
+extern "C" {
+intptr_t SyscallAsm(intptr_t nr, const intptr_t args[6]);
+}
+#elif defined(__mips__)
+extern "C" {
+intptr_t SyscallAsm(intptr_t nr, const intptr_t args[8]);
+}
+#endif
+
+}  // namespace
+
+intptr_t Syscall::InvalidCall() {
+  // Explicitly pass eight zero arguments just in case.
+  return Call(kInvalidSyscallNumber, 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+intptr_t Syscall::Call(int nr,
+                       intptr_t p0,
+                       intptr_t p1,
+                       intptr_t p2,
+                       intptr_t p3,
+                       intptr_t p4,
+                       intptr_t p5,
+                       intptr_t p6,
+                       intptr_t p7) {
+  // We rely on "intptr_t" to be the exact size as a "void *". This is
+  // typically true, but just in case, we add a check. The language
+  // specification allows platforms some leeway in cases, where
+  // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect
+  // that this would only be an issue for IA64, which we are currently not
+  // planning on supporting. And it is even possible that this would work
+  // on IA64, but for lack of actual hardware, I cannot test.
+  static_assert(sizeof(void*) == sizeof(intptr_t),
+                "pointer types and intptr_t must be exactly the same size");
+
+  // TODO(nedeljko): Enable use of more than six parameters on architectures
+  //                 where that makes sense.
+#if defined(__mips__)
+  const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7};
+#else
+  DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not "
+                      "added for this architecture";
+  DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not "
+                      "added for this architecture";
+  const intptr_t args[6] = {p0, p1, p2, p3, p4, p5};
+#endif  // defined(__mips__)
+
+// Invoke our file-scope assembly code. The constraints have been picked
+// carefully to match what the rest of the assembly code expects in input,
+// output, and clobbered registers.
+#if defined(__i386__)
+  intptr_t ret = nr;
+  asm volatile(
+      "call SyscallAsm\n"
+      // N.B. These are not the calling conventions normally used by the ABI.
+      : "=a"(ret)
+      : "0"(ret), "D"(args)
+      : "cc", "esp", "memory", "ecx", "edx");
+#elif defined(__x86_64__)
+  intptr_t ret = SyscallAsm(nr, args);
+#elif defined(__arm__)
+  intptr_t ret;
+  {
+    register intptr_t inout __asm__("r0") = nr;
+    register const intptr_t* data __asm__("r6") = args;
+    asm volatile(
+        "bl SyscallAsm\n"
+        // N.B. These are not the calling conventions normally used by the ABI.
+        : "=r"(inout)
+        : "0"(inout), "r"(data)
+        : "cc",
+          "lr",
+          "memory",
+          "r1",
+          "r2",
+          "r3",
+          "r4",
+          "r5"
+#if !defined(__thumb__)
+          // In thumb mode, we cannot use "r7" as a general purpose register, as
+          // it is our frame pointer. We have to manually manage and preserve
+          // it.
+          // In ARM mode, we have a dedicated frame pointer register and "r7" is
+          // thus available as a general purpose register. We don't preserve it,
+          // but instead mark it as clobbered.
+          ,
+          "r7"
+#endif  // !defined(__thumb__)
+        );
+    ret = inout;
+  }
+#elif defined(__mips__)
+  int err_status;
+  intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status);
+
+  if (err_status) {
+    // On error, MIPS returns errno from syscall instead of -errno.
+    // The purpose of this negation is for SandboxSyscall() to behave
+    // more like it would on other architectures.
+    ret = -ret;
+  }
+#elif defined(__aarch64__)
+  intptr_t ret;
+  {
+    register intptr_t inout __asm__("x0") = nr;
+    register const intptr_t* data __asm__("x6") = args;
+    asm volatile("bl SyscallAsm\n"
+                 : "=r"(inout)
+                 : "0"(inout), "r"(data)
+                 : "memory", "x1", "x2", "x3", "x4", "x5", "x8", "x30");
+    ret = inout;
+  }
+
+#else
+#error "Unimplemented architecture"
+#endif
+  return ret;
+}
+
+void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) {
+#if defined(__mips__)
+  // Mips ABI states that on error a3 CPU register has non zero value and if
+  // there is no error, it should be zero.
+  if (ret_val <= -1 && ret_val >= -4095) {
+    // |ret_val| followes the Syscall::Call() convention of being -errno on
+    // errors. In order to write correct value to return register this sign
+    // needs to be changed back.
+    ret_val = -ret_val;
+    SECCOMP_PARM4(ctx) = 1;
+  } else
+    SECCOMP_PARM4(ctx) = 0;
+#endif
+  SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val);
+}
+
+#if defined(__mips__)
+intptr_t Syscall::SandboxSyscallRaw(int nr,
+                                    const intptr_t* args,
+                                    intptr_t* err_ret) {
+  register intptr_t ret __asm__("v0") = nr;
+  register intptr_t syscallasm __asm__("t9") = (intptr_t) &SyscallAsm;
+  // a3 register becomes non zero on error.
+  register intptr_t err_stat __asm__("a3") = 0;
+  {
+    register const intptr_t* data __asm__("a0") = args;
+    asm volatile(
+        "jalr $t9\n"
+        " nop\n"
+        : "=r"(ret), "=r"(err_stat)
+        : "0"(ret),
+          "r"(data),
+          "r"(syscallasm)
+          // a2 is in the clober list so inline assembly can not change its
+          // value.
+        : "memory", "ra", "a2");
+  }
+
+  // Set an error status so it can be used outside of this function
+  *err_ret = err_stat;
+
+  return ret;
+}
+#endif  // defined(__mips__)
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf/syscall.h b/libchrome/sandbox/linux/seccomp-bpf/syscall.h
new file mode 100644
index 0000000..ccfc88d
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/syscall.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
+
+#include <signal.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This purely static class can be used to perform system calls with some
+// low-level control.
+class SANDBOX_EXPORT Syscall {
+ public:
+  // InvalidCall() invokes Call() with a platform-appropriate syscall
+  // number that is guaranteed to not be implemented (i.e., normally
+  // returns -ENOSYS).
+  // This is primarily meant to be useful for writing sandbox policy
+  // unit tests.
+  static intptr_t InvalidCall();
+
+  // System calls can take up to six parameters (up to eight on some
+  // architectures). Traditionally, glibc
+  // implements this property by using variadic argument lists. This works, but
+  // confuses modern tools such as valgrind, because we are nominally passing
+  // uninitialized data whenever we call through this function and pass less
+  // than the full six arguments.
+  // So, instead, we use C++'s template system to achieve a very similar
+  // effect. C++ automatically sets the unused parameters to zero for us, and
+  // it also does the correct type expansion (e.g. from 32bit to 64bit) where
+  // necessary.
+  // We have to use C-style cast operators as we want to be able to accept both
+  // integer and pointer types.
+  template <class T0,
+            class T1,
+            class T2,
+            class T3,
+            class T4,
+            class T5,
+            class T6,
+            class T7>
+  static inline intptr_t
+  Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) {
+    return Call(nr,
+                (intptr_t)p0,
+                (intptr_t)p1,
+                (intptr_t)p2,
+                (intptr_t)p3,
+                (intptr_t)p4,
+                (intptr_t)p5,
+                (intptr_t)p6,
+                (intptr_t)p7);
+  }
+
+  template <class T0,
+            class T1,
+            class T2,
+            class T3,
+            class T4,
+            class T5,
+            class T6>
+  static inline intptr_t
+  Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6) {
+    return Call(nr,
+                (intptr_t)p0,
+                (intptr_t)p1,
+                (intptr_t)p2,
+                (intptr_t)p3,
+                (intptr_t)p4,
+                (intptr_t)p5,
+                (intptr_t)p6,
+                0);
+  }
+
+  template <class T0, class T1, class T2, class T3, class T4, class T5>
+  static inline intptr_t
+  Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) {
+    return Call(nr,
+                (intptr_t)p0,
+                (intptr_t)p1,
+                (intptr_t)p2,
+                (intptr_t)p3,
+                (intptr_t)p4,
+                (intptr_t)p5,
+                0,
+                0);
+  }
+
+  template <class T0, class T1, class T2, class T3, class T4>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) {
+    return Call(nr, p0, p1, p2, p3, p4, 0, 0, 0);
+  }
+
+  template <class T0, class T1, class T2, class T3>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3) {
+    return Call(nr, p0, p1, p2, p3, 0, 0, 0, 0);
+  }
+
+  template <class T0, class T1, class T2>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2) {
+    return Call(nr, p0, p1, p2, 0, 0, 0, 0, 0);
+  }
+
+  template <class T0, class T1>
+  static inline intptr_t Call(int nr, T0 p0, T1 p1) {
+    return Call(nr, p0, p1, 0, 0, 0, 0, 0, 0);
+  }
+
+  template <class T0>
+  static inline intptr_t Call(int nr, T0 p0) {
+    return Call(nr, p0, 0, 0, 0, 0, 0, 0, 0);
+  }
+
+  static inline intptr_t Call(int nr) {
+    return Call(nr, 0, 0, 0, 0, 0, 0, 0, 0);
+  }
+
+  // Set the registers in |ctx| to match what they would be after a system call
+  // returning |ret_val|. |ret_val| must follow the Syscall::Call() convention
+  // of being -errno on errors.
+  static void PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx);
+
+ private:
+  // This performs system call |nr| with the arguments p0 to p7 from a constant
+  // userland address, which is for instance observable by seccomp-bpf filters.
+  // The constant userland address from which these system calls are made will
+  // be returned if |nr| is passed as -1.
+  // On error, this function will return a value between -1 and -4095 which
+  // should be interpreted as -errno.
+  static intptr_t Call(int nr,
+                       intptr_t p0,
+                       intptr_t p1,
+                       intptr_t p2,
+                       intptr_t p3,
+                       intptr_t p4,
+                       intptr_t p5,
+                       intptr_t p6,
+                       intptr_t p7);
+
+#if defined(__mips__)
+  // This function basically does on MIPS what SandboxSyscall() is doing on
+  // other architectures. However, because of specificity of MIPS regarding
+  // handling syscall errors, SandboxSyscall() is made as a wrapper for this
+  // function in order for SandboxSyscall() to behave more like on other
+  // architectures on places where return value from SandboxSyscall() is used
+  // directly (like in most tests).
+  // The syscall "nr" is called with arguments that are set in an array on which
+  // pointer "args" points to and an information weather there is an error or no
+  // is returned to SandboxSyscall() by err_stat.
+  static intptr_t SandboxSyscallRaw(int nr,
+                                    const intptr_t* args,
+                                    intptr_t* err_stat);
+#endif  // defined(__mips__)
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Syscall);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
diff --git a/libchrome/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/libchrome/sandbox/linux/seccomp-bpf/syscall_unittest.cc
new file mode 100644
index 0000000..01336f9
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -0,0 +1,244 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::ResultExpr;
+using sandbox::bpf_dsl::Trap;
+
+namespace sandbox {
+
+namespace {
+
+// Different platforms use different symbols for the six-argument version
+// of the mmap() system call. Test for the correct symbol at compile time.
+#ifdef __NR_mmap2
+const int kMMapNr = __NR_mmap2;
+#else
+const int kMMapNr = __NR_mmap;
+#endif
+
+TEST(Syscall, InvalidCallReturnsENOSYS) {
+  EXPECT_EQ(-ENOSYS, Syscall::InvalidCall());
+}
+
+TEST(Syscall, WellKnownEntryPoint) {
+// Test that Syscall::Call(-1) is handled specially. Don't do this on ARM,
+// where syscall(-1) crashes with SIGILL. Not running the test is fine, as we
+// are still testing ARM code in the next set of tests.
+#if !defined(__arm__) && !defined(__aarch64__)
+  EXPECT_NE(Syscall::Call(-1), syscall(-1));
+#endif
+
+// If possible, test that Syscall::Call(-1) returns the address right
+// after
+// a kernel entry point.
+#if defined(__i386__)
+  EXPECT_EQ(0x80CDu, ((uint16_t*)Syscall::Call(-1))[-1]);  // INT 0x80
+#elif defined(__x86_64__)
+  EXPECT_EQ(0x050Fu, ((uint16_t*)Syscall::Call(-1))[-1]);  // SYSCALL
+#elif defined(__arm__)
+#if defined(__thumb__)
+  EXPECT_EQ(0xDF00u, ((uint16_t*)Syscall::Call(-1))[-1]);  // SWI 0
+#else
+  EXPECT_EQ(0xEF000000u, ((uint32_t*)Syscall::Call(-1))[-1]);  // SVC 0
+#endif
+#elif defined(__mips__)
+  // Opcode for MIPS sycall is in the lower 16-bits
+  EXPECT_EQ(0x0cu, (((uint32_t*)Syscall::Call(-1))[-1]) & 0x0000FFFF);
+#elif defined(__aarch64__)
+  EXPECT_EQ(0xD4000001u, ((uint32_t*)Syscall::Call(-1))[-1]);  // SVC 0
+#else
+#warning Incomplete test case; need port for target platform
+#endif
+}
+
+TEST(Syscall, TrivialSyscallNoArgs) {
+  // Test that we can do basic system calls
+  EXPECT_EQ(Syscall::Call(__NR_getpid), syscall(__NR_getpid));
+}
+
+TEST(Syscall, TrivialSyscallOneArg) {
+  int new_fd;
+  // Duplicate standard error and close it.
+  ASSERT_GE(new_fd = Syscall::Call(__NR_dup, 2), 0);
+  int close_return_value = IGNORE_EINTR(Syscall::Call(__NR_close, new_fd));
+  ASSERT_EQ(close_return_value, 0);
+}
+
+TEST(Syscall, TrivialFailingSyscall) {
+  errno = -42;
+  int ret = Syscall::Call(__NR_dup, -1);
+  ASSERT_EQ(-EBADF, ret);
+  // Verify that Syscall::Call does not touch errno.
+  ASSERT_EQ(-42, errno);
+}
+
+// SIGSYS trap handler that will be called on __NR_uname.
+intptr_t CopySyscallArgsToAux(const struct arch_seccomp_data& args, void* aux) {
+  // |aux| is our BPF_AUX pointer.
+  std::vector<uint64_t>* const seen_syscall_args =
+      static_cast<std::vector<uint64_t>*>(aux);
+  BPF_ASSERT(arraysize(args.args) == 6);
+  seen_syscall_args->assign(args.args, args.args + arraysize(args.args));
+  return -ENOMEM;
+}
+
+class CopyAllArgsOnUnamePolicy : public bpf_dsl::Policy {
+ public:
+  explicit CopyAllArgsOnUnamePolicy(std::vector<uint64_t>* aux) : aux_(aux) {}
+  ~CopyAllArgsOnUnamePolicy() override {}
+
+  ResultExpr EvaluateSyscall(int sysno) const override {
+    DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+    if (sysno == __NR_uname) {
+      return Trap(CopySyscallArgsToAux, aux_);
+    } else {
+      return Allow();
+    }
+  }
+
+ private:
+  std::vector<uint64_t>* aux_;
+
+  DISALLOW_COPY_AND_ASSIGN(CopyAllArgsOnUnamePolicy);
+};
+
+// We are testing Syscall::Call() by making use of a BPF filter that
+// allows us
+// to inspect the system call arguments that the kernel saw.
+BPF_TEST(Syscall,
+         SyntheticSixArgs,
+         CopyAllArgsOnUnamePolicy,
+         std::vector<uint64_t> /* (*BPF_AUX) */) {
+  const int kExpectedValue = 42;
+  // In this test we only pass integers to the kernel. We might want to make
+  // additional tests to try other types. What we will see depends on
+  // implementation details of kernel BPF filters and we will need to document
+  // the expected behavior very clearly.
+  int syscall_args[6];
+  for (size_t i = 0; i < arraysize(syscall_args); ++i) {
+    syscall_args[i] = kExpectedValue + i;
+  }
+
+  // We could use pretty much any system call we don't need here. uname() is
+  // nice because it doesn't have any dangerous side effects.
+  BPF_ASSERT(Syscall::Call(__NR_uname,
+                           syscall_args[0],
+                           syscall_args[1],
+                           syscall_args[2],
+                           syscall_args[3],
+                           syscall_args[4],
+                           syscall_args[5]) == -ENOMEM);
+
+  // We expect the trap handler to have copied the 6 arguments.
+  BPF_ASSERT(BPF_AUX->size() == 6);
+
+  // Don't loop here so that we can see which argument does cause the failure
+  // easily from the failing line.
+  // uint64_t is the type passed to our SIGSYS handler.
+  BPF_ASSERT((*BPF_AUX)[0] == static_cast<uint64_t>(syscall_args[0]));
+  BPF_ASSERT((*BPF_AUX)[1] == static_cast<uint64_t>(syscall_args[1]));
+  BPF_ASSERT((*BPF_AUX)[2] == static_cast<uint64_t>(syscall_args[2]));
+  BPF_ASSERT((*BPF_AUX)[3] == static_cast<uint64_t>(syscall_args[3]));
+  BPF_ASSERT((*BPF_AUX)[4] == static_cast<uint64_t>(syscall_args[4]));
+  BPF_ASSERT((*BPF_AUX)[5] == static_cast<uint64_t>(syscall_args[5]));
+}
+
+TEST(Syscall, ComplexSyscallSixArgs) {
+  int fd;
+  ASSERT_LE(0,
+            fd = Syscall::Call(__NR_openat, AT_FDCWD, "/dev/null", O_RDWR, 0L));
+
+  // Use mmap() to allocate some read-only memory
+  char* addr0;
+  ASSERT_NE(
+      (char*)NULL,
+      addr0 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+                                                    (void*)NULL,
+                                                    4096,
+                                                    PROT_READ,
+                                                    MAP_PRIVATE | MAP_ANONYMOUS,
+                                                    fd,
+                                                    0L)));
+
+  // Try to replace the existing mapping with a read-write mapping
+  char* addr1;
+  ASSERT_EQ(addr0,
+            addr1 = reinterpret_cast<char*>(
+                Syscall::Call(kMMapNr,
+                              addr0,
+                              4096L,
+                              PROT_READ | PROT_WRITE,
+                              MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+                              fd,
+                              0L)));
+  ++*addr1;  // This should not seg fault
+
+  // Clean up
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, 4096L));
+  EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
+
+  // Check that the offset argument (i.e. the sixth argument) is processed
+  // correctly.
+  ASSERT_GE(
+      fd = Syscall::Call(__NR_openat, AT_FDCWD, "/proc/self/exe", O_RDONLY, 0L),
+      0);
+  char* addr2, *addr3;
+  ASSERT_NE((char*)NULL,
+            addr2 = reinterpret_cast<char*>(Syscall::Call(
+                kMMapNr, (void*)NULL, 8192L, PROT_READ, MAP_PRIVATE, fd, 0L)));
+  ASSERT_NE((char*)NULL,
+            addr3 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+                                                          (void*)NULL,
+                                                          4096L,
+                                                          PROT_READ,
+                                                          MAP_PRIVATE,
+                                                          fd,
+#if defined(__NR_mmap2)
+                                                          1L
+#else
+                                                          4096L
+#endif
+                                                          )));
+  EXPECT_EQ(0, memcmp(addr2 + 4096, addr3, 4096));
+
+  // Just to be absolutely on the safe side, also verify that the file
+  // contents matches what we are getting from a read() operation.
+  char buf[8192];
+  EXPECT_EQ(8192, Syscall::Call(__NR_read, fd, buf, 8192L));
+  EXPECT_EQ(0, memcmp(addr2, buf, 8192));
+
+  // Clean up
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 8192L));
+  EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, 4096L));
+  EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf/trap.cc b/libchrome/sandbox/linux/seccomp-bpf/trap.cc
new file mode 100644
index 0000000..003708d
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/trap.cc
@@ -0,0 +1,387 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/trap.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include <algorithm>
+#include <limits>
+#include <tuple>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace {
+
+struct arch_sigsys {
+  void* ip;
+  int nr;
+  unsigned int arch;
+};
+
+const int kCapacityIncrement = 20;
+
+// Unsafe traps can only be turned on, if the user explicitly allowed them
+// by setting the CHROME_SANDBOX_DEBUGGING environment variable.
+const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
+
+// We need to tell whether we are performing a "normal" callback, or
+// whether we were called recursively from within a UnsafeTrap() callback.
+// This is a little tricky to do, because we need to somehow get access to
+// per-thread data from within a signal context. Normal TLS storage is not
+// safely accessible at this time. We could roll our own, but that involves
+// a lot of complexity. Instead, we co-opt one bit in the signal mask.
+// If BUS is blocked, we assume that we have been called recursively.
+// There is a possibility for collision with other code that needs to do
+// this, but in practice the risks are low.
+// If SIGBUS turns out to be a problem, we could instead co-opt one of the
+// realtime signals. There are plenty of them. Unfortunately, there is no
+// way to mark a signal as allocated. So, the potential for collision is
+// possibly even worse.
+bool GetIsInSigHandler(const ucontext_t* ctx) {
+  // Note: on Android, sigismember does not take a pointer to const.
+  return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), LINUX_SIGBUS);
+}
+
+void SetIsInSigHandler() {
+  sigset_t mask;
+  if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGBUS) ||
+      sandbox::sys_sigprocmask(LINUX_SIG_BLOCK, &mask, NULL)) {
+    SANDBOX_DIE("Failed to block SIGBUS");
+  }
+}
+
+bool IsDefaultSignalAction(const struct sigaction& sa) {
+  if (sa.sa_flags & SA_SIGINFO || sa.sa_handler != SIG_DFL) {
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+namespace sandbox {
+
+Trap::Trap()
+    : trap_array_(NULL),
+      trap_array_size_(0),
+      trap_array_capacity_(0),
+      has_unsafe_traps_(false) {
+  // Set new SIGSYS handler
+  struct sigaction sa = {};
+  // In some toolchain, sa_sigaction is not declared in struct sigaction.
+  // So, here cast the pointer to the sa_handler's type. This works because
+  // |sa_handler| and |sa_sigaction| shares the same memory.
+  sa.sa_handler = reinterpret_cast<void (*)(int)>(SigSysAction);
+  sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER;
+  struct sigaction old_sa = {};
+  if (sys_sigaction(LINUX_SIGSYS, &sa, &old_sa) < 0) {
+    SANDBOX_DIE("Failed to configure SIGSYS handler");
+  }
+
+  if (!IsDefaultSignalAction(old_sa)) {
+    static const char kExistingSIGSYSMsg[] =
+        "Existing signal handler when trying to install SIGSYS. SIGSYS needs "
+        "to be reserved for seccomp-bpf.";
+    DLOG(FATAL) << kExistingSIGSYSMsg;
+    LOG(ERROR) << kExistingSIGSYSMsg;
+  }
+
+  // Unmask SIGSYS
+  sigset_t mask;
+  if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGSYS) ||
+      sys_sigprocmask(LINUX_SIG_UNBLOCK, &mask, NULL)) {
+    SANDBOX_DIE("Failed to configure SIGSYS handler");
+  }
+}
+
+bpf_dsl::TrapRegistry* Trap::Registry() {
+  // Note: This class is not thread safe. It is the caller's responsibility
+  // to avoid race conditions. Normally, this is a non-issue as the sandbox
+  // can only be initialized if there are no other threads present.
+  // Also, this is not a normal singleton. Once created, the global trap
+  // object must never be destroyed again.
+  if (!global_trap_) {
+    global_trap_ = new Trap();
+    if (!global_trap_) {
+      SANDBOX_DIE("Failed to allocate global trap handler");
+    }
+  }
+  return global_trap_;
+}
+
+void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) {
+  if (info) {
+    MSAN_UNPOISON(info, sizeof(*info));
+  }
+
+  // Obtain the signal context. This, most notably, gives us access to
+  // all CPU registers at the time of the signal.
+  ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+  if (ctx) {
+    MSAN_UNPOISON(ctx, sizeof(*ctx));
+  }
+
+  if (!global_trap_) {
+    RAW_SANDBOX_DIE(
+        "This can't happen. Found no global singleton instance "
+        "for Trap() handling.");
+  }
+  global_trap_->SigSys(nr, info, ctx);
+}
+
+void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) {
+  // Signal handlers should always preserve "errno". Otherwise, we could
+  // trigger really subtle bugs.
+  const int old_errno = errno;
+
+  // Various sanity checks to make sure we actually received a signal
+  // triggered by a BPF filter. If something else triggered SIGSYS
+  // (e.g. kill()), there is really nothing we can do with this signal.
+  if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !ctx ||
+      info->si_errno <= 0 ||
+      static_cast<size_t>(info->si_errno) > trap_array_size_) {
+    // ATI drivers seem to send SIGSYS, so this cannot be FATAL.
+    // See crbug.com/178166.
+    // TODO(jln): add a DCHECK or move back to FATAL.
+    RAW_LOG(ERROR, "Unexpected SIGSYS received.");
+    errno = old_errno;
+    return;
+  }
+
+
+  // Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
+  // most versions of glibc don't include this information in siginfo_t. So,
+  // we need to explicitly copy it into a arch_sigsys structure.
+  struct arch_sigsys sigsys;
+  memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
+
+#if defined(__mips__)
+  // When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the
+  // number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the
+  // real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx)
+  bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) &&
+                          sigsys.nr != static_cast<int>(SECCOMP_PARM1(ctx));
+#else
+  bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx));
+#endif
+
+  // Some more sanity checks.
+  if (sigsys.ip != reinterpret_cast<void*>(SECCOMP_IP(ctx)) ||
+      sigsys_nr_is_bad || sigsys.arch != SECCOMP_ARCH) {
+    // TODO(markus):
+    // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
+    // safe and can lead to bugs. We should eventually implement a different
+    // logging and reporting mechanism that is safe to be called from
+    // the sigSys() handler.
+    RAW_SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.");
+  }
+
+  intptr_t rc;
+  if (has_unsafe_traps_ && GetIsInSigHandler(ctx)) {
+    errno = old_errno;
+    if (sigsys.nr == __NR_clone) {
+      RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
+    }
+#if defined(__mips__)
+    // Mips supports up to eight arguments for syscall.
+    // However, seccomp bpf can filter only up to six arguments, so using eight
+    // arguments has sense only when using UnsafeTrap() handler.
+    rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
+                       SECCOMP_PARM1(ctx),
+                       SECCOMP_PARM2(ctx),
+                       SECCOMP_PARM3(ctx),
+                       SECCOMP_PARM4(ctx),
+                       SECCOMP_PARM5(ctx),
+                       SECCOMP_PARM6(ctx),
+                       SECCOMP_PARM7(ctx),
+                       SECCOMP_PARM8(ctx));
+#else
+    rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
+                       SECCOMP_PARM1(ctx),
+                       SECCOMP_PARM2(ctx),
+                       SECCOMP_PARM3(ctx),
+                       SECCOMP_PARM4(ctx),
+                       SECCOMP_PARM5(ctx),
+                       SECCOMP_PARM6(ctx));
+#endif  // defined(__mips__)
+  } else {
+    const TrapKey& trap = trap_array_[info->si_errno - 1];
+    if (!trap.safe) {
+      SetIsInSigHandler();
+    }
+
+    // Copy the seccomp-specific data into a arch_seccomp_data structure. This
+    // is what we are showing to TrapFnc callbacks that the system call
+    // evaluator registered with the sandbox.
+    struct arch_seccomp_data data = {
+        static_cast<int>(SECCOMP_SYSCALL(ctx)),
+        SECCOMP_ARCH,
+        reinterpret_cast<uint64_t>(sigsys.ip),
+        {static_cast<uint64_t>(SECCOMP_PARM1(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM2(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM3(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM4(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM5(ctx)),
+         static_cast<uint64_t>(SECCOMP_PARM6(ctx))}};
+
+    // Now call the TrapFnc callback associated with this particular instance
+    // of SECCOMP_RET_TRAP.
+    rc = trap.fnc(data, const_cast<void*>(trap.aux));
+  }
+
+  // Update the CPU register that stores the return code of the system call
+  // that we just handled, and restore "errno" to the value that it had
+  // before entering the signal handler.
+  Syscall::PutValueInUcontext(rc, ctx);
+  errno = old_errno;
+
+  return;
+}
+
+bool Trap::TrapKey::operator<(const TrapKey& o) const {
+  return std::tie(fnc, aux, safe) < std::tie(o.fnc, o.aux, o.safe);
+}
+
+uint16_t Trap::Add(TrapFnc fnc, const void* aux, bool safe) {
+  if (!safe && !SandboxDebuggingAllowedByUser()) {
+    // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable,
+    // we never return an ErrorCode that is marked as "unsafe". This also
+    // means, the BPF compiler will never emit code that allow unsafe system
+    // calls to by-pass the filter (because they use the magic return address
+    // from Syscall::Call(-1)).
+
+    // This SANDBOX_DIE() can optionally be removed. It won't break security,
+    // but it might make error messages from the BPF compiler a little harder
+    // to understand. Removing the SANDBOX_DIE() allows callers to easily check
+    // whether unsafe traps are supported (by checking whether the returned
+    // ErrorCode is ET_INVALID).
+    SANDBOX_DIE(
+        "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
+        "is enabled");
+
+    return 0;
+  }
+
+  // Each unique pair of TrapFnc and auxiliary data make up a distinct instance
+  // of a SECCOMP_RET_TRAP.
+  TrapKey key(fnc, aux, safe);
+
+  // We return unique identifiers together with SECCOMP_RET_TRAP. This allows
+  // us to associate trap with the appropriate handler. The kernel allows us
+  // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to
+  // avoid 0, as it could be confused for a trap without any specific id.
+  // The nice thing about sequentially numbered identifiers is that we can also
+  // trivially look them up from our signal handler without making any system
+  // calls that might be async-signal-unsafe.
+  // In order to do so, we store all of our traps in a C-style trap_array_.
+
+  TrapIds::const_iterator iter = trap_ids_.find(key);
+  if (iter != trap_ids_.end()) {
+    // We have seen this pair before. Return the same id that we assigned
+    // earlier.
+    return iter->second;
+  }
+
+  // This is a new pair. Remember it and assign a new id.
+  if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ ||
+      trap_array_size_ >= std::numeric_limits<uint16_t>::max()) {
+    // In practice, this is pretty much impossible to trigger, as there
+    // are other kernel limitations that restrict overall BPF program sizes.
+    SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances");
+  }
+
+  // Our callers ensure that there are no other threads accessing trap_array_
+  // concurrently (typically this is done by ensuring that we are single-
+  // threaded while the sandbox is being set up). But we nonetheless are
+  // modifying a live data structure that could be accessed any time a
+  // system call is made; as system calls could be triggering SIGSYS.
+  // So, we have to be extra careful that we update trap_array_ atomically.
+  // In particular, this means we shouldn't be using realloc() to resize it.
+  // Instead, we allocate a new array, copy the values, and then switch the
+  // pointer. We only really care about the pointer being updated atomically
+  // and the data that is pointed to being valid, as these are the only
+  // values accessed from the signal handler. It is OK if trap_array_size_
+  // is inconsistent with the pointer, as it is monotonously increasing.
+  // Also, we only care about compiler barriers, as the signal handler is
+  // triggered synchronously from a system call. We don't have to protect
+  // against issues with the memory model or with completely asynchronous
+  // events.
+  if (trap_array_size_ >= trap_array_capacity_) {
+    trap_array_capacity_ += kCapacityIncrement;
+    TrapKey* old_trap_array = trap_array_;
+    TrapKey* new_trap_array = new TrapKey[trap_array_capacity_];
+    std::copy_n(old_trap_array, trap_array_size_, new_trap_array);
+
+    // Language specs are unclear on whether the compiler is allowed to move
+    // the "delete[]" above our preceding assignments and/or memory moves,
+    // iff the compiler believes that "delete[]" doesn't have any other
+    // global side-effects.
+    // We insert optimization barriers to prevent this from happening.
+    // The first barrier is probably not needed, but better be explicit in
+    // what we want to tell the compiler.
+    // The clang developer mailing list couldn't answer whether this is a
+    // legitimate worry; but they at least thought that the barrier is
+    // sufficient to prevent the (so far hypothetical) problem of re-ordering
+    // of instructions by the compiler.
+    //
+    // TODO(mdempsky): Try to clean this up using base/atomicops or C++11
+    // atomics; see crbug.com/414363.
+    asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory");
+    trap_array_ = new_trap_array;
+    asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory");
+
+    delete[] old_trap_array;
+  }
+
+  uint16_t id = trap_array_size_ + 1;
+  trap_ids_[key] = id;
+  trap_array_[trap_array_size_] = key;
+  trap_array_size_++;
+  return id;
+}
+
+bool Trap::SandboxDebuggingAllowedByUser() {
+  const char* debug_flag = getenv(kSandboxDebuggingEnv);
+  return debug_flag && *debug_flag;
+}
+
+bool Trap::EnableUnsafeTraps() {
+  if (!has_unsafe_traps_) {
+    // Unsafe traps are a one-way fuse. Once enabled, they can never be turned
+    // off again.
+    // We only allow enabling unsafe traps, if the user explicitly set an
+    // appropriate environment variable. This prevents bugs that accidentally
+    // disable all sandboxing for all users.
+    if (SandboxDebuggingAllowedByUser()) {
+      // We only ever print this message once, when we enable unsafe traps the
+      // first time.
+      SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes");
+      has_unsafe_traps_ = true;
+    } else {
+      SANDBOX_INFO(
+          "Cannot disable sandbox and use unsafe traps unless "
+          "CHROME_SANDBOX_DEBUGGING is turned on first");
+    }
+  }
+  // Returns the, possibly updated, value of has_unsafe_traps_.
+  return has_unsafe_traps_;
+}
+
+Trap* Trap::global_trap_;
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/seccomp-bpf/trap.h b/libchrome/sandbox/linux/seccomp-bpf/trap.h
new file mode 100644
index 0000000..a73d206
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/trap.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 SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// The Trap class allows a BPF filter program to branch out to user space by
+// raising a SIGSYS signal.
+// N.B.: This class does not perform any synchronization operations. If
+//   modifications are made to any of the traps, it is the caller's
+//   responsibility to ensure that this happens in a thread-safe fashion.
+//   Preferably, that means that no other threads should be running at that
+//   time. For the purposes of our sandbox, this assertion should always be
+//   true. Threads are incompatible with the seccomp sandbox anyway.
+class SANDBOX_EXPORT Trap : public bpf_dsl::TrapRegistry {
+ public:
+  uint16_t Add(TrapFnc fnc, const void* aux, bool safe) override;
+
+  bool EnableUnsafeTraps() override;
+
+  // Registry returns the trap registry used by Trap's SIGSYS handler,
+  // creating it if necessary.
+  static bpf_dsl::TrapRegistry* Registry();
+
+  // SandboxDebuggingAllowedByUser returns whether the
+  // "CHROME_SANDBOX_DEBUGGING" environment variable is set.
+  static bool SandboxDebuggingAllowedByUser();
+
+ private:
+  struct TrapKey {
+    TrapKey() : fnc(NULL), aux(NULL), safe(false) {}
+    TrapKey(TrapFnc f, const void* a, bool s) : fnc(f), aux(a), safe(s) {}
+    TrapFnc fnc;
+    const void* aux;
+    bool safe;
+    bool operator<(const TrapKey&) const;
+  };
+  typedef std::map<TrapKey, uint16_t> TrapIds;
+
+  // Our constructor is private. A shared global instance is created
+  // automatically as needed.
+  Trap();
+
+  // The destructor is unimplemented as destroying this object would
+  // break subsequent system calls that trigger a SIGSYS.
+  ~Trap() = delete;
+
+  static void SigSysAction(int nr, LinuxSigInfo* info, void* void_context);
+
+  // Make sure that SigSys is not inlined in order to get slightly better crash
+  // dumps.
+  void SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx)
+      __attribute__((noinline));
+  // We have a global singleton that handles all of our SIGSYS traps. This
+  // variable must never be deallocated after it has been set up initially, as
+  // there is no way to reset in-kernel BPF filters that generate SIGSYS
+  // events.
+  static Trap* global_trap_;
+
+  TrapIds trap_ids_;            // Maps from TrapKeys to numeric ids
+  TrapKey* trap_array_;         // Array of TrapKeys indexed by ids
+  size_t trap_array_size_;      // Currently used size of array
+  size_t trap_array_capacity_;  // Currently allocated capacity of array
+  bool has_unsafe_traps_;       // Whether unsafe traps have been enabled
+
+  // Copying and assigning is unimplemented. It doesn't make sense for a
+  // singleton.
+  DISALLOW_COPY_AND_ASSIGN(Trap);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
diff --git a/libchrome/sandbox/linux/seccomp-bpf/trap_unittest.cc b/libchrome/sandbox/linux/seccomp-bpf/trap_unittest.cc
new file mode 100644
index 0000000..99f94bf
--- /dev/null
+++ b/libchrome/sandbox/linux/seccomp-bpf/trap_unittest.cc
@@ -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.
+
+#include "sandbox/linux/seccomp-bpf/trap.h"
+
+#include <signal.h>
+
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+namespace {
+
+SANDBOX_TEST_ALLOW_NOISE(Trap, SigSysAction) {
+  // This creates a global Trap instance, and registers the signal handler
+  // (Trap::SigSysAction).
+  Trap::Registry();
+
+  // Send SIGSYS to self. If signal handler (SigSysAction) is not registered,
+  // the process will be terminated with status code -SIGSYS.
+  // Note that, SigSysAction handler would output an error message
+  // "Unexpected SIGSYS received." so it is necessary to allow the noise.
+  raise(SIGSYS);
+}
+
+}  // namespace
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/DEPS b/libchrome/sandbox/linux/services/DEPS
new file mode 100644
index 0000000..70d9b18
--- /dev/null
+++ b/libchrome/sandbox/linux/services/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox/linux/system_headers",
+]
diff --git a/libchrome/sandbox/linux/services/credentials.cc b/libchrome/sandbox/linux/services/credentials.cc
new file mode 100644
index 0000000..0c617d4
--- /dev/null
+++ b/libchrome/sandbox/linux/services/credentials.cc
@@ -0,0 +1,335 @@
+// 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 "sandbox/linux/services/credentials.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
+#include "sandbox/linux/services/namespace_utils.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace sandbox {
+
+namespace {
+
+bool IsRunningOnValgrind() { return RUNNING_ON_VALGRIND; }
+
+// Checks that the set of RES-uids and the set of RES-gids have
+// one element each and return that element in |resuid| and |resgid|
+// respectively. It's ok to pass NULL as one or both of the ids.
+bool GetRESIds(uid_t* resuid, gid_t* resgid) {
+  uid_t ruid, euid, suid;
+  gid_t rgid, egid, sgid;
+  PCHECK(sys_getresuid(&ruid, &euid, &suid) == 0);
+  PCHECK(sys_getresgid(&rgid, &egid, &sgid) == 0);
+  const bool uids_are_equal = (ruid == euid) && (ruid == suid);
+  const bool gids_are_equal = (rgid == egid) && (rgid == sgid);
+  if (!uids_are_equal || !gids_are_equal) return false;
+  if (resuid) *resuid = euid;
+  if (resgid) *resgid = egid;
+  return true;
+}
+
+const int kExitSuccess = 0;
+
+#if defined(__clang__)
+// Disable sanitizers that rely on TLS and may write to non-stack memory.
+__attribute__((no_sanitize_address))
+__attribute__((no_sanitize_thread))
+__attribute__((no_sanitize_memory))
+#endif
+int ChrootToSelfFdinfo(void*) {
+  // This function can be run from a vforked child, so it should not write to
+  // any memory other than the stack or errno. Reads from TLS may be different
+  // from in the parent process.
+  RAW_CHECK(sys_chroot("/proc/self/fdinfo/") == 0);
+
+  // CWD is essentially an implicit file descriptor, so be careful to not
+  // leave it behind.
+  RAW_CHECK(chdir("/") == 0);
+  _exit(kExitSuccess);
+}
+
+// chroot() to an empty dir that is "safe". To be safe, it must not contain
+// any subdirectory (chroot-ing there would allow a chroot escape) and it must
+// be impossible to create an empty directory there.
+// We achieve this by doing the following:
+// 1. We create a new process sharing file system information.
+// 2. In the child, we chroot to /proc/self/fdinfo/
+// This is already "safe", since fdinfo/ does not contain another directory and
+// one cannot create another directory there.
+// 3. The process dies
+// After (3) happens, the directory is not available anymore in /proc.
+bool ChrootToSafeEmptyDir() {
+  // We need to chroot to a fdinfo that is unique to a process and have that
+  // process die.
+  // 1. We don't want to simply fork() because duplicating the page tables is
+  // slow with a big address space.
+  // 2. We do not use a regular thread (that would unshare CLONE_FILES) because
+  // when we are in a PID namespace, we cannot easily get a handle to the
+  // /proc/tid directory for the thread (since /proc may not be aware of the
+  // PID namespace). With a process, we can just use /proc/self.
+  pid_t pid = -1;
+  char stack_buf[PTHREAD_STACK_MIN] ALIGNAS(16);
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS_FAMILY)
+  // The stack grows downward.
+  void* stack = stack_buf + sizeof(stack_buf);
+#else
+#error "Unsupported architecture"
+#endif
+
+  int clone_flags = CLONE_FS | LINUX_SIGCHLD;
+  void* tls = nullptr;
+#if defined(ARCH_CPU_X86_64) || defined(ARCH_CPU_ARM_FAMILY)
+  // Use CLONE_VM | CLONE_VFORK as an optimization to avoid copying page tables.
+  // Since clone writes to the new child's TLS before returning, we must set a
+  // new TLS to avoid corrupting the current process's TLS. On ARCH_CPU_X86,
+  // glibc performs syscalls by calling a function pointer in TLS, so we do not
+  // attempt this optimization.
+  clone_flags |= CLONE_VM | CLONE_VFORK | CLONE_SETTLS;
+
+  char tls_buf[PTHREAD_STACK_MIN] = {0};
+  tls = tls_buf;
+#endif
+
+  pid = clone(ChrootToSelfFdinfo, stack, clone_flags, nullptr, nullptr, tls,
+              nullptr);
+  PCHECK(pid != -1);
+
+  int status = -1;
+  PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
+
+  return WIFEXITED(status) && WEXITSTATUS(status) == kExitSuccess;
+}
+
+// CHECK() that an attempt to move to a new user namespace raised an expected
+// errno.
+void CheckCloneNewUserErrno(int error) {
+  // EPERM can happen if already in a chroot. EUSERS if too many nested
+  // namespaces are used. EINVAL for kernels that don't support the feature.
+  // Valgrind will ENOSYS unshare().
+  PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
+         error == ENOSYS);
+}
+
+// Converts a Capability to the corresponding Linux CAP_XXX value.
+int CapabilityToKernelValue(Credentials::Capability cap) {
+  switch (cap) {
+    case Credentials::Capability::SYS_CHROOT:
+      return CAP_SYS_CHROOT;
+    case Credentials::Capability::SYS_ADMIN:
+      return CAP_SYS_ADMIN;
+  }
+
+  LOG(FATAL) << "Invalid Capability: " << static_cast<int>(cap);
+  return 0;
+}
+
+}  // namespace.
+
+// static
+bool Credentials::DropAllCapabilities(int proc_fd) {
+  if (!SetCapabilities(proc_fd, std::vector<Capability>())) {
+    return false;
+  }
+
+  CHECK(!HasAnyCapability());
+  return true;
+}
+
+// static
+bool Credentials::DropAllCapabilities() {
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+  return Credentials::DropAllCapabilities(proc_fd.get());
+}
+
+// static
+bool Credentials::DropAllCapabilitiesOnCurrentThread() {
+  return SetCapabilitiesOnCurrentThread(std::vector<Capability>());
+}
+
+// static
+bool Credentials::SetCapabilitiesOnCurrentThread(
+    const std::vector<Capability>& caps) {
+  struct cap_hdr hdr = {};
+  hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
+
+  // Initially, cap has no capability flags set. Enable the effective and
+  // permitted flags only for the requested capabilities.
+  for (const Capability cap : caps) {
+    const int cap_num = CapabilityToKernelValue(cap);
+    const size_t index = CAP_TO_INDEX(cap_num);
+    const uint32_t mask = CAP_TO_MASK(cap_num);
+    data[index].effective |= mask;
+    data[index].permitted |= mask;
+  }
+
+  return sys_capset(&hdr, data) == 0;
+}
+
+// static
+bool Credentials::SetCapabilities(int proc_fd,
+                                  const std::vector<Capability>& caps) {
+  DCHECK_LE(0, proc_fd);
+
+#if !defined(THREAD_SANITIZER)
+  // With TSAN, accept to break the security model as it is a testing
+  // configuration.
+  CHECK(ThreadHelpers::IsSingleThreaded(proc_fd));
+#endif
+
+  return SetCapabilitiesOnCurrentThread(caps);
+}
+
+bool Credentials::HasAnyCapability() {
+  struct cap_hdr hdr = {};
+  hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
+
+  PCHECK(sys_capget(&hdr, data) == 0);
+
+  for (size_t i = 0; i < arraysize(data); ++i) {
+    if (data[i].effective || data[i].permitted || data[i].inheritable) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool Credentials::HasCapability(Capability cap) {
+  struct cap_hdr hdr = {};
+  hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  struct cap_data data[_LINUX_CAPABILITY_U32S_3] = {{}};
+
+  PCHECK(sys_capget(&hdr, data) == 0);
+
+  const int cap_num = CapabilityToKernelValue(cap);
+  const size_t index = CAP_TO_INDEX(cap_num);
+  const uint32_t mask = CAP_TO_MASK(cap_num);
+
+  return (data[index].effective | data[index].permitted |
+          data[index].inheritable) &
+         mask;
+}
+
+// static
+bool Credentials::CanCreateProcessInNewUserNS() {
+  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
+  // so always consider UserNS unsupported there.
+  if (IsRunningOnValgrind()) {
+    return false;
+  }
+
+#if defined(THREAD_SANITIZER)
+  // With TSAN, processes will always have threads running and can never
+  // enter a new user namespace with MoveToNewUserNS().
+  return false;
+#endif
+
+  // This is roughly a fork().
+  const pid_t pid = sys_clone(CLONE_NEWUSER | SIGCHLD, 0, 0, 0, 0);
+
+  if (pid == -1) {
+    CheckCloneNewUserErrno(errno);
+    return false;
+  }
+
+  // The parent process could have had threads. In the child, these threads
+  // have disappeared. Make sure to not do anything in the child, as this is a
+  // fragile execution environment.
+  if (pid == 0) {
+    _exit(kExitSuccess);
+  }
+
+  // Always reap the child.
+  int status = -1;
+  PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
+  CHECK(WIFEXITED(status));
+  CHECK_EQ(kExitSuccess, WEXITSTATUS(status));
+
+  // clone(2) succeeded, we can use CLONE_NEWUSER.
+  return true;
+}
+
+bool Credentials::MoveToNewUserNS() {
+  uid_t uid;
+  gid_t gid;
+  if (!GetRESIds(&uid, &gid)) {
+    // If all the uids (or gids) are not equal to each other, the security
+    // model will most likely confuse the caller, abort.
+    DVLOG(1) << "uids or gids differ!";
+    return false;
+  }
+  int ret = sys_unshare(CLONE_NEWUSER);
+  if (ret) {
+    const int unshare_errno = errno;
+    VLOG(1) << "Looks like unprivileged CLONE_NEWUSER may not be available "
+            << "on this kernel.";
+    CheckCloneNewUserErrno(unshare_errno);
+    return false;
+  }
+
+  if (NamespaceUtils::KernelSupportsDenySetgroups()) {
+    PCHECK(NamespaceUtils::DenySetgroups());
+  }
+
+  // The current {r,e,s}{u,g}id is now an overflow id (c.f.
+  // /proc/sys/kernel/overflowuid). Setup the uid and gid maps.
+  DCHECK(GetRESIds(NULL, NULL));
+  const char kGidMapFile[] = "/proc/self/gid_map";
+  const char kUidMapFile[] = "/proc/self/uid_map";
+  PCHECK(NamespaceUtils::WriteToIdMapFile(kGidMapFile, gid));
+  PCHECK(NamespaceUtils::WriteToIdMapFile(kUidMapFile, uid));
+  DCHECK(GetRESIds(NULL, NULL));
+  return true;
+}
+
+bool Credentials::DropFileSystemAccess(int proc_fd) {
+  CHECK_LE(0, proc_fd);
+
+  CHECK(ChrootToSafeEmptyDir());
+  CHECK(!base::DirectoryExists(base::FilePath("/proc")));
+  CHECK(!ProcUtil::HasOpenDirectory(proc_fd));
+  // We never let this function fail.
+  return true;
+}
+
+pid_t Credentials::ForkAndDropCapabilitiesInChild() {
+  pid_t pid = fork();
+  if (pid != 0) {
+    return pid;
+  }
+
+  // Since we just forked, we are single threaded.
+  PCHECK(DropAllCapabilitiesOnCurrentThread());
+  return 0;
+}
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/services/credentials.h b/libchrome/sandbox/linux/services/credentials.h
new file mode 100644
index 0000000..b89a6aa
--- /dev/null
+++ b/libchrome/sandbox/linux/services/credentials.h
@@ -0,0 +1,106 @@
+// 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 SANDBOX_LINUX_SERVICES_CREDENTIALS_H_
+#define SANDBOX_LINUX_SERVICES_CREDENTIALS_H_
+
+#include "build/build_config.h"
+// Link errors are tedious to track, raise a compile-time error instead.
+#if defined(OS_ANDROID)
+#error "Android is not supported."
+#endif  // defined(OS_ANDROID).
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This class should be used to manipulate the current process' credentials.
+// It is currently a stub used to manipulate POSIX.1e capabilities as
+// implemented by the Linux kernel.
+class SANDBOX_EXPORT Credentials {
+ public:
+  // For brevity, we only expose enums for the subset of capabilities we use.
+  // This can be expanded as the need arises.
+  enum class Capability {
+    SYS_CHROOT,
+    SYS_ADMIN,
+  };
+
+  // Drop all capabilities in the effective, inheritable and permitted sets for
+  // the current thread. For security reasons, since capabilities are
+  // per-thread, the caller is responsible for ensuring it is single-threaded
+  // when calling this API.
+  // |proc_fd| must be a file descriptor to /proc/ and remains owned by
+  // the caller.
+  static bool DropAllCapabilities(int proc_fd) WARN_UNUSED_RESULT;
+  // A similar API which assumes that it can open /proc/self/ by itself.
+  static bool DropAllCapabilities() WARN_UNUSED_RESULT;
+  // Sets the effective and permitted capability sets for the current thread to
+  // the list of capabiltiies in |caps|. All other capability flags are cleared.
+  static bool SetCapabilities(int proc_fd,
+                              const std::vector<Capability>& caps)
+      WARN_UNUSED_RESULT;
+
+  // Versions of the above functions which do not check that the process is
+  // single-threaded. After calling these functions, capabilities of other
+  // threads will not be changed. This is dangerous, do not use unless you nkow
+  // what you are doing.
+  static bool DropAllCapabilitiesOnCurrentThread() WARN_UNUSED_RESULT;
+  static bool SetCapabilitiesOnCurrentThread(
+      const std::vector<Capability>& caps) WARN_UNUSED_RESULT;
+
+  // Returns true if the current thread has either the effective, permitted, or
+  // inheritable flag set for the given capability.
+  static bool HasCapability(Capability cap);
+
+  // Return true iff there is any capability in any of the capabilities sets
+  // of the current thread.
+  static bool HasAnyCapability();
+
+  // Returns whether the kernel supports CLONE_NEWUSER and whether it would be
+  // possible to immediately move to a new user namespace. There is no point
+  // in using this method right before calling MoveToNewUserNS(), simply call
+  // MoveToNewUserNS() immediately. This method is only useful to test the
+  // ability to move to a user namespace ahead of time.
+  static bool CanCreateProcessInNewUserNS();
+
+  // Move the current process to a new "user namespace" as supported by Linux
+  // 3.8+ (CLONE_NEWUSER).
+  // The uid map will be set-up so that the perceived uid and gid will not
+  // change.
+  // If this call succeeds, the current process will be granted a full set of
+  // capabilities in the new namespace.
+  // This will fail if the process is not mono-threaded.
+  static bool MoveToNewUserNS() WARN_UNUSED_RESULT;
+
+  // Remove the ability of the process to access the file system. File
+  // descriptors which are already open prior to calling this API remain
+  // available.
+  // The implementation currently uses chroot(2) and requires CAP_SYS_CHROOT.
+  // CAP_SYS_CHROOT can be acquired by using the MoveToNewUserNS() API.
+  // |proc_fd| must be a file descriptor to /proc/ and must be the only open
+  // directory file descriptor of the process.
+  //
+  // CRITICAL:
+  //   - the caller must close |proc_fd| eventually or access to the file
+  // system can be recovered.
+  //   - DropAllCapabilities() must be called to prevent escapes.
+  static bool DropFileSystemAccess(int proc_fd) WARN_UNUSED_RESULT;
+
+  // Forks and drops capabilities in the child.
+  static pid_t ForkAndDropCapabilitiesInChild();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Credentials);
+};
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SERVICES_CREDENTIALS_H_
diff --git a/libchrome/sandbox/linux/services/credentials_unittest.cc b/libchrome/sandbox/linux/services/credentials_unittest.cc
new file mode 100644
index 0000000..b95ba0b
--- /dev/null
+++ b/libchrome/sandbox/linux/services/credentials_unittest.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 "sandbox/linux/services/credentials.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+struct CapFreeDeleter {
+  inline void operator()(cap_t cap) const {
+    int ret = cap_free(cap);
+    CHECK_EQ(0, ret);
+  }
+};
+
+// Wrapper to manage libcap2's cap_t type.
+typedef std::unique_ptr<typeof(*((cap_t)0)), CapFreeDeleter> ScopedCap;
+
+bool WorkingDirectoryIsRoot() {
+  char current_dir[PATH_MAX];
+  char* cwd = getcwd(current_dir, sizeof(current_dir));
+  PCHECK(cwd);
+  if (strcmp("/", cwd)) return false;
+
+  // The current directory is the root. Add a few paranoid checks.
+  struct stat current;
+  CHECK_EQ(0, stat(".", &current));
+  struct stat parrent;
+  CHECK_EQ(0, stat("..", &parrent));
+  CHECK_EQ(current.st_dev, parrent.st_dev);
+  CHECK_EQ(current.st_ino, parrent.st_ino);
+  CHECK_EQ(current.st_mode, parrent.st_mode);
+  CHECK_EQ(current.st_uid, parrent.st_uid);
+  CHECK_EQ(current.st_gid, parrent.st_gid);
+  return true;
+}
+
+SANDBOX_TEST(Credentials, DropAllCaps) {
+  CHECK(Credentials::DropAllCapabilities());
+  CHECK(!Credentials::HasAnyCapability());
+}
+
+SANDBOX_TEST(Credentials, MoveToNewUserNS) {
+  CHECK(Credentials::DropAllCapabilities());
+  bool moved_to_new_ns = Credentials::MoveToNewUserNS();
+  fprintf(stdout,
+          "Unprivileged CLONE_NEWUSER supported: %s\n",
+          moved_to_new_ns ? "true." : "false.");
+  fflush(stdout);
+  if (!moved_to_new_ns) {
+    fprintf(stdout, "This kernel does not support unprivileged namespaces. "
+            "USERNS tests will succeed without running.\n");
+    fflush(stdout);
+    return;
+  }
+  CHECK(Credentials::HasAnyCapability());
+  CHECK(Credentials::DropAllCapabilities());
+  CHECK(!Credentials::HasAnyCapability());
+}
+
+SANDBOX_TEST(Credentials, CanCreateProcessInNewUserNS) {
+  CHECK(Credentials::DropAllCapabilities());
+  bool user_ns_supported = Credentials::CanCreateProcessInNewUserNS();
+  bool moved_to_new_ns = Credentials::MoveToNewUserNS();
+  CHECK_EQ(user_ns_supported, moved_to_new_ns);
+}
+
+SANDBOX_TEST(Credentials, UidIsPreserved) {
+  CHECK(Credentials::DropAllCapabilities());
+  uid_t old_ruid, old_euid, old_suid;
+  gid_t old_rgid, old_egid, old_sgid;
+  PCHECK(0 == getresuid(&old_ruid, &old_euid, &old_suid));
+  PCHECK(0 == getresgid(&old_rgid, &old_egid, &old_sgid));
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  uid_t new_ruid, new_euid, new_suid;
+  PCHECK(0 == getresuid(&new_ruid, &new_euid, &new_suid));
+  CHECK(old_ruid == new_ruid);
+  CHECK(old_euid == new_euid);
+  CHECK(old_suid == new_suid);
+
+  gid_t new_rgid, new_egid, new_sgid;
+  PCHECK(0 == getresgid(&new_rgid, &new_egid, &new_sgid));
+  CHECK(old_rgid == new_rgid);
+  CHECK(old_egid == new_egid);
+  CHECK(old_sgid == new_sgid);
+}
+
+bool NewUserNSCycle() {
+  if (!Credentials::MoveToNewUserNS() ||
+      !Credentials::HasAnyCapability() ||
+      !Credentials::DropAllCapabilities() ||
+      Credentials::HasAnyCapability()) {
+    return false;
+  }
+  return true;
+}
+
+SANDBOX_TEST(Credentials, NestedUserNS) {
+  CHECK(Credentials::DropAllCapabilities());
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropAllCapabilities());
+  // As of 3.12, the kernel has a limit of 32. See create_user_ns().
+  const int kNestLevel = 10;
+  for (int i = 0; i < kNestLevel; ++i) {
+    CHECK(NewUserNSCycle()) << "Creating new user NS failed at iteration "
+                                  << i << ".";
+  }
+}
+
+// Test the WorkingDirectoryIsRoot() helper.
+SANDBOX_TEST(Credentials, CanDetectRoot) {
+  PCHECK(0 == chdir("/proc/"));
+  CHECK(!WorkingDirectoryIsRoot());
+  PCHECK(0 == chdir("/"));
+  CHECK(WorkingDirectoryIsRoot());
+}
+
+// Disabled on ASAN because of crbug.com/451603.
+SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(DropFileSystemAccessIsSafe)) {
+  CHECK(Credentials::DropAllCapabilities());
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
+  CHECK(!base::DirectoryExists(base::FilePath("/proc")));
+  CHECK(WorkingDirectoryIsRoot());
+  CHECK(base::IsDirectoryEmpty(base::FilePath("/")));
+  // We want the chroot to never have a subdirectory. A subdirectory
+  // could allow a chroot escape.
+  CHECK_NE(0, mkdir("/test", 0700));
+}
+
+// Check that after dropping filesystem access and dropping privileges
+// it is not possible to regain capabilities.
+SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(CannotRegainPrivileges)) {
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+  CHECK(Credentials::DropAllCapabilities(proc_fd.get()));
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropFileSystemAccess(proc_fd.get()));
+  CHECK(Credentials::DropAllCapabilities(proc_fd.get()));
+
+  // The kernel should now prevent us from regaining capabilities because we
+  // are in a chroot.
+  CHECK(!Credentials::CanCreateProcessInNewUserNS());
+  CHECK(!Credentials::MoveToNewUserNS());
+}
+
+SANDBOX_TEST(Credentials, SetCapabilities) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS())
+    return;
+
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_ADMIN));
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
+
+  std::vector<Credentials::Capability> caps;
+  caps.push_back(Credentials::Capability::SYS_CHROOT);
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
+
+  CHECK(!Credentials::HasCapability(Credentials::Capability::SYS_ADMIN));
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
+
+  const std::vector<Credentials::Capability> no_caps;
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), no_caps));
+  CHECK(!Credentials::HasAnyCapability());
+}
+
+SANDBOX_TEST(Credentials, SetCapabilitiesAndChroot) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS())
+    return;
+
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+
+  CHECK(Credentials::HasCapability(Credentials::Capability::SYS_CHROOT));
+  PCHECK(chroot("/") == 0);
+
+  std::vector<Credentials::Capability> caps;
+  caps.push_back(Credentials::Capability::SYS_CHROOT);
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
+  PCHECK(chroot("/") == 0);
+
+  CHECK(Credentials::DropAllCapabilities());
+  PCHECK(chroot("/") == -1 && errno == EPERM);
+}
+
+SANDBOX_TEST(Credentials, SetCapabilitiesMatchesLibCap2) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS())
+    return;
+
+  base::ScopedFD proc_fd(ProcUtil::OpenProc());
+
+  std::vector<Credentials::Capability> caps;
+  caps.push_back(Credentials::Capability::SYS_CHROOT);
+  CHECK(Credentials::SetCapabilities(proc_fd.get(), caps));
+
+  ScopedCap actual_cap(cap_get_proc());
+  PCHECK(actual_cap != nullptr);
+
+  ScopedCap expected_cap(cap_init());
+  PCHECK(expected_cap != nullptr);
+
+  const cap_value_t allowed_cap = CAP_SYS_CHROOT;
+  for (const cap_flag_t flag : {CAP_EFFECTIVE, CAP_PERMITTED}) {
+    PCHECK(cap_set_flag(expected_cap.get(), flag, 1, &allowed_cap, CAP_SET) ==
+           0);
+  }
+
+  CHECK_EQ(0, cap_compare(expected_cap.get(), actual_cap.get()));
+}
+
+volatile sig_atomic_t signal_handler_called;
+void SignalHandler(int sig) {
+  signal_handler_called = 1;
+}
+
+// Disabled on ASAN because of crbug.com/451603.
+SANDBOX_TEST(Credentials, DISABLE_ON_ASAN(DropFileSystemAccessPreservesTLS)) {
+  // Probably missing kernel support.
+  if (!Credentials::MoveToNewUserNS()) return;
+  CHECK(Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
+
+  // In glibc, pthread_getattr_np makes an assertion about the cached PID/TID in
+  // TLS.
+  pthread_attr_t attr;
+  EXPECT_EQ(0, pthread_getattr_np(pthread_self(), &attr));
+
+  // raise also uses the cached TID in glibc.
+  struct sigaction action = {};
+  action.sa_handler = &SignalHandler;
+  PCHECK(sigaction(SIGUSR1, &action, nullptr) == 0);
+
+  PCHECK(raise(SIGUSR1) == 0);
+  CHECK_EQ(1, signal_handler_called);
+}
+
+}  // namespace.
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/services/init_process_reaper.cc b/libchrome/sandbox/linux/services/init_process_reaper.cc
new file mode 100644
index 0000000..2ff18b5
--- /dev/null
+++ b/libchrome/sandbox/linux/services/init_process_reaper.cc
@@ -0,0 +1,101 @@
+// 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 "sandbox/linux/services/init_process_reaper.h"
+
+#include <signal.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace sandbox {
+
+namespace {
+
+void DoNothingSignalHandler(int signal) {}
+
+}  // namespace
+
+bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback) {
+  int sync_fds[2];
+  // We want to use send, so we can't use a pipe
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {
+    PLOG(ERROR) << "Failed to create socketpair";
+    return false;
+  }
+  pid_t child_pid = fork();
+  if (child_pid == -1) {
+    int close_ret;
+    close_ret = IGNORE_EINTR(close(sync_fds[0]));
+    DPCHECK(!close_ret);
+    close_ret = IGNORE_EINTR(close(sync_fds[1]));
+    DPCHECK(!close_ret);
+    return false;
+  }
+  if (child_pid) {
+    // In the parent, assuming the role of an init process.
+    // The disposition for SIGCHLD cannot be SIG_IGN or wait() will only return
+    // once all of our childs are dead. Since we're init we need to reap childs
+    // as they come.
+    struct sigaction action;
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = &DoNothingSignalHandler;
+    CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
+
+    int close_ret;
+    close_ret = IGNORE_EINTR(close(sync_fds[0]));
+    DPCHECK(!close_ret);
+    close_ret = shutdown(sync_fds[1], SHUT_RD);
+    DPCHECK(!close_ret);
+    if (post_fork_parent_callback)
+      post_fork_parent_callback->Run();
+    // Tell the child to continue
+    CHECK(HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) == 1);
+    close_ret = IGNORE_EINTR(close(sync_fds[1]));
+    DPCHECK(!close_ret);
+
+    for (;;) {
+      // Loop until we have reaped our one natural child
+      siginfo_t reaped_child_info;
+      int wait_ret =
+          HANDLE_EINTR(waitid(P_ALL, 0, &reaped_child_info, WEXITED));
+      if (wait_ret)
+        _exit(1);
+      if (reaped_child_info.si_pid == child_pid) {
+        int exit_code = 0;
+        // We're done waiting
+        if (reaped_child_info.si_code == CLD_EXITED) {
+          exit_code = reaped_child_info.si_status;
+        }
+        // Exit with the same exit code as our child. Exit with 0 if we got
+        // signaled.
+        _exit(exit_code);
+      }
+    }
+  } else {
+    // The child needs to wait for the parent to run the callback to avoid a
+    // race condition.
+    int close_ret;
+    close_ret = IGNORE_EINTR(close(sync_fds[1]));
+    DPCHECK(!close_ret);
+    close_ret = shutdown(sync_fds[0], SHUT_WR);
+    DPCHECK(!close_ret);
+    char should_continue;
+    int read_ret = HANDLE_EINTR(read(sync_fds[0], &should_continue, 1));
+    close_ret = IGNORE_EINTR(close(sync_fds[0]));
+    DPCHECK(!close_ret);
+    if (read_ret == 1)
+      return true;
+    else
+      return false;
+  }
+}
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/services/init_process_reaper.h b/libchrome/sandbox/linux/services/init_process_reaper.h
new file mode 100644
index 0000000..840f6fc
--- /dev/null
+++ b/libchrome/sandbox/linux/services/init_process_reaper.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SERVICES_INIT_PROCESS_REAPER_H_
+#define SANDBOX_LINUX_SERVICES_INIT_PROCESS_REAPER_H_
+
+#include "base/callback_forward.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// The current process will fork(). The parent will become a process reaper
+// like init(1). The child will continue normally (after this function
+// returns).
+// If not NULL, |post_fork_parent_callback| will run in the parent almost
+// immediately after fork().
+// Since this function calls fork(), it's very important that the caller has
+// only one thread running.
+SANDBOX_EXPORT bool CreateInitProcessReaper(
+    base::Closure* post_fork_parent_callback);
+
+}  // namespace sandbox.
+
+#endif  // SANDBOX_LINUX_SERVICES_INIT_PROCESS_REAPER_H_
diff --git a/libchrome/sandbox/linux/services/namespace_sandbox.cc b/libchrome/sandbox/linux/services/namespace_sandbox.cc
new file mode 100644
index 0000000..00e5947
--- /dev/null
+++ b/libchrome/sandbox/linux/services/namespace_sandbox.cc
@@ -0,0 +1,245 @@
+// 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 "sandbox/linux/services/namespace_sandbox.h"
+
+#include <sched.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_utils.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace sandbox {
+
+namespace {
+
+const char kSandboxUSERNSEnvironmentVarName[] = "SBX_USER_NS";
+const char kSandboxPIDNSEnvironmentVarName[] = "SBX_PID_NS";
+const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS";
+
+#if !defined(OS_NACL_NONSFI)
+class WriteUidGidMapDelegate : public base::LaunchOptions::PreExecDelegate {
+ public:
+  WriteUidGidMapDelegate()
+      : uid_(getuid()),
+        gid_(getgid()),
+        supports_deny_setgroups_(
+            NamespaceUtils::KernelSupportsDenySetgroups()) {}
+
+  ~WriteUidGidMapDelegate() override {}
+
+  void RunAsyncSafe() override {
+    if (supports_deny_setgroups_) {
+      RAW_CHECK(NamespaceUtils::DenySetgroups());
+    }
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/uid_map", uid_));
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/gid_map", gid_));
+  }
+
+ private:
+  const uid_t uid_;
+  const gid_t gid_;
+  const bool supports_deny_setgroups_;
+  DISALLOW_COPY_AND_ASSIGN(WriteUidGidMapDelegate);
+};
+
+void SetEnvironForNamespaceType(base::EnvironmentMap* environ,
+                                base::NativeEnvironmentString env_var,
+                                bool value) {
+  // An empty string causes the env var to be unset in the child process.
+  (*environ)[env_var] = value ? "1" : "";
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+// Linux supports up to 64 signals. This should be updated if that ever changes.
+int g_signal_exit_codes[64];
+
+void TerminationSignalHandler(int sig) {
+  // Return a special exit code so that the process is detected as terminated by
+  // a signal.
+  const size_t sig_idx = static_cast<size_t>(sig);
+  if (sig_idx < arraysize(g_signal_exit_codes)) {
+    _exit(g_signal_exit_codes[sig_idx]);
+  }
+
+  _exit(NamespaceSandbox::SignalExitCode(sig));
+}
+
+}  // namespace
+
+#if !defined(OS_NACL_NONSFI)
+NamespaceSandbox::Options::Options()
+    : ns_types(CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET),
+      fail_on_unsupported_ns_type(false) {}
+
+NamespaceSandbox::Options::~Options() {}
+
+// static
+base::Process NamespaceSandbox::LaunchProcess(
+    const base::CommandLine& cmdline,
+    const base::LaunchOptions& launch_options) {
+  return LaunchProcessWithOptions(cmdline.argv(), launch_options, Options());
+}
+
+// static
+base::Process NamespaceSandbox::LaunchProcess(
+    const std::vector<std::string>& argv,
+    const base::LaunchOptions& launch_options) {
+  return LaunchProcessWithOptions(argv, launch_options, Options());
+}
+
+// static
+base::Process NamespaceSandbox::LaunchProcessWithOptions(
+    const base::CommandLine& cmdline,
+    const base::LaunchOptions& launch_options,
+    const Options& ns_sandbox_options) {
+  return LaunchProcessWithOptions(cmdline.argv(), launch_options,
+                                  ns_sandbox_options);
+}
+
+// static
+base::Process NamespaceSandbox::LaunchProcessWithOptions(
+    const std::vector<std::string>& argv,
+    const base::LaunchOptions& launch_options,
+    const Options& ns_sandbox_options) {
+  // These fields may not be set by the caller.
+  CHECK(launch_options.pre_exec_delegate == nullptr);
+  CHECK_EQ(0, launch_options.clone_flags);
+
+  int clone_flags = 0;
+  const int kSupportedTypes[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET};
+  for (const int ns_type : kSupportedTypes) {
+    if ((ns_type & ns_sandbox_options.ns_types) == 0) {
+      continue;
+    }
+
+    if (NamespaceUtils::KernelSupportsUnprivilegedNamespace(ns_type)) {
+      clone_flags |= ns_type;
+    } else if (ns_sandbox_options.fail_on_unsupported_ns_type) {
+      return base::Process();
+    }
+  }
+  CHECK(clone_flags & CLONE_NEWUSER);
+
+  WriteUidGidMapDelegate write_uid_gid_map_delegate;
+
+  base::LaunchOptions launch_options_copy = launch_options;
+  launch_options_copy.pre_exec_delegate = &write_uid_gid_map_delegate;
+  launch_options_copy.clone_flags = clone_flags;
+
+  const std::pair<int, const char*> clone_flag_environ[] = {
+      std::make_pair(CLONE_NEWUSER, kSandboxUSERNSEnvironmentVarName),
+      std::make_pair(CLONE_NEWPID, kSandboxPIDNSEnvironmentVarName),
+      std::make_pair(CLONE_NEWNET, kSandboxNETNSEnvironmentVarName),
+  };
+
+  base::EnvironmentMap* environ = &launch_options_copy.environ;
+  for (const auto& entry : clone_flag_environ) {
+    const int flag = entry.first;
+    const char* environ_name = entry.second;
+    SetEnvironForNamespaceType(environ, environ_name, clone_flags & flag);
+  }
+
+  return base::LaunchProcess(argv, launch_options_copy);
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+// static
+pid_t NamespaceSandbox::ForkInNewPidNamespace(bool drop_capabilities_in_child) {
+  const pid_t pid =
+      base::ForkWithFlags(CLONE_NEWPID | LINUX_SIGCHLD, nullptr, nullptr);
+  if (pid < 0) {
+    return pid;
+  }
+
+  if (pid == 0) {
+    DCHECK_EQ(1, getpid());
+    if (drop_capabilities_in_child) {
+      // Since we just forked, we are single-threaded, so this should be safe.
+      CHECK(Credentials::DropAllCapabilitiesOnCurrentThread());
+    }
+    return 0;
+  }
+
+  return pid;
+}
+
+// static
+void NamespaceSandbox::InstallDefaultTerminationSignalHandlers() {
+  static const int kDefaultTermSignals[] = {
+      LINUX_SIGHUP,  LINUX_SIGINT,  LINUX_SIGABRT, LINUX_SIGQUIT,
+      LINUX_SIGPIPE, LINUX_SIGTERM, LINUX_SIGUSR1, LINUX_SIGUSR2,
+  };
+
+  for (const int sig : kDefaultTermSignals) {
+    InstallTerminationSignalHandler(sig, SignalExitCode(sig));
+  }
+}
+
+// static
+bool NamespaceSandbox::InstallTerminationSignalHandler(
+    int sig,
+    int exit_code) {
+  struct sigaction old_action;
+  PCHECK(sys_sigaction(sig, nullptr, &old_action) == 0);
+
+#if !defined(OS_NACL_NONSFI)
+  if (old_action.sa_flags & SA_SIGINFO &&
+      old_action.sa_sigaction != nullptr) {
+    return false;
+  }
+#endif
+
+  if (old_action.sa_handler != LINUX_SIG_DFL) {
+    return false;
+  }
+
+  const size_t sig_idx = static_cast<size_t>(sig);
+  CHECK_LT(sig_idx, arraysize(g_signal_exit_codes));
+
+  DCHECK_GE(exit_code, 0);
+  DCHECK_LT(exit_code, 256);
+
+  g_signal_exit_codes[sig_idx] = exit_code;
+
+  struct sigaction action = {};
+  action.sa_handler = &TerminationSignalHandler;
+  PCHECK(sys_sigaction(sig, &action, nullptr) == 0);
+  return true;
+}
+
+// static
+bool NamespaceSandbox::InNewUserNamespace() {
+  return getenv(kSandboxUSERNSEnvironmentVarName) != nullptr;
+}
+
+// static
+bool NamespaceSandbox::InNewPidNamespace() {
+  return getenv(kSandboxPIDNSEnvironmentVarName) != nullptr;
+}
+
+// static
+bool NamespaceSandbox::InNewNetNamespace() {
+  return getenv(kSandboxNETNSEnvironmentVarName) != nullptr;
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/namespace_sandbox.h b/libchrome/sandbox/linux/services/namespace_sandbox.h
new file mode 100644
index 0000000..b5832fb
--- /dev/null
+++ b/libchrome/sandbox/linux/services/namespace_sandbox.h
@@ -0,0 +1,126 @@
+// 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 SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
+#define SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
+
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Helper class for starting a process inside a new user, PID, and network
+// namespace. Before using a namespace sandbox, check for namespaces support
+// using Credentials::CanCreateProcessInNewUserNS.
+//
+// A typical use for "A" launching a sandboxed process "B" would be:
+// 1. A sets up a command line and launch options for process B.
+// 2. A launches B with LaunchProcess.
+// 3. B should be prepared to assume the role of init(1). In particular, apart
+//    from SIGKILL and SIGSTOP, B cannot receive any signal for which it does
+//    not have an explicit signal handler registered.
+//    If B dies, all the processes in the namespace will die.
+//    B can fork() and the parent can assume the role of init(1), by using
+//    CreateInitProcessReaper().
+// 4. B chroots using Credentials::MoveToNewUserNS() and
+//    Credentials::DropFileSystemAccess()
+// 5. B drops capabilities gained by entering the new user namespace with
+//    Credentials::DropAllCapabilities().
+class SANDBOX_EXPORT NamespaceSandbox {
+ public:
+#if !defined(OS_NACL_NONSFI)
+  struct Options {
+    Options();
+    ~Options();
+
+    // Bitmask of namespace types. Must be some combination of CLONE_NEWUSER
+    // (required), CLONE_NEWPID, and CLONE_NEWNET. Defaults to all of the above.
+    int ns_types;
+
+    // Fail if any of the namespace types are not supported. Defaults to false.
+    bool fail_on_unsupported_ns_type;
+  };
+
+  // Launch a new process inside its own user/PID/network namespaces (depending
+  // on kernel support). Requires at a minimum that user namespaces are
+  // supported (use Credentials::CanCreateProcessInNewUserNS to check this).
+  //
+  // pre_exec_delegate and clone_flags fields of LaunchOptions should be nullptr
+  // and 0, respectively, since this function makes a copy of options and
+  // overrides them.
+  static base::Process LaunchProcess(const base::CommandLine& cmdline,
+                                     const base::LaunchOptions& launch_options);
+  static base::Process LaunchProcess(const std::vector<std::string>& argv,
+                                     const base::LaunchOptions& launch_options);
+
+  // Versions which take namespace sandbox options. These allow fine grained
+  // control over the types of namespaces used.
+  static base::Process LaunchProcessWithOptions(
+      const base::CommandLine& cmdline,
+      const base::LaunchOptions& launch_options,
+      const Options& ns_sandbox_options);
+  static base::Process LaunchProcessWithOptions(
+      const std::vector<std::string>& argv,
+      const base::LaunchOptions& launch_options,
+      const Options& ns_sandbox_options);
+#endif  // !defined(OS_NACL_NONSFI)
+
+  // Forks a process in its own PID namespace. The child process is the init
+  // process inside of the PID namespace, so if the child needs to fork further,
+  // it should call CreateInitProcessReaper, which turns the init process into a
+  // reaper process.
+  //
+  // Otherwise, the child should setup handlers for signals which should
+  // terminate the process using InstallDefaultTerminationSignalHandlers or
+  // InstallTerminationSignalHandler. This works around the fact that init
+  // processes ignore such signals unless they have an explicit handler set.
+  //
+  // This function requries CAP_SYS_ADMIN. If |drop_capabilities_in_child| is
+  // true, then capabilities are dropped in the child.
+  static pid_t ForkInNewPidNamespace(bool drop_capabilities_in_child);
+
+  // Installs a signal handler for:
+  //
+  // SIGHUP, SIGINT, SIGABRT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
+  //
+  // that exits with SignalExitCode(sig). These are signals whose default action
+  // is to terminate the program (apart from SIGILL, SIGFPE, and SIGSEGV, which
+  // will still terminate the process if e.g. an illegal instruction is
+  // encountered, etc.).
+  //
+  // If any of these already had a signal handler installed, this function will
+  // not override them.
+  static void InstallDefaultTerminationSignalHandlers();
+
+  // Installs a signal handler for |sig| which exits with |exit_code|. If a
+  // signal handler was already present for |sig|, does nothing and returns
+  // false.
+  static bool InstallTerminationSignalHandler(int sig, int exit_code);
+
+  // Returns an exit code corresponding to the process being killed by sig. This
+  // is the same as exit code that NaCl's default signal handler uses.
+  static int SignalExitCode(int sig) { return -sig & 0xff; }
+
+  // Returns whether the namespace sandbox created a new user, PID, and network
+  // namespace. In particular, InNewUserNamespace should return true iff the
+  // process was started via this class.
+  static bool InNewUserNamespace();
+  static bool InNewPidNamespace();
+  static bool InNewNetNamespace();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceSandbox);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
diff --git a/libchrome/sandbox/linux/services/namespace_sandbox_unittest.cc b/libchrome/sandbox/linux/services/namespace_sandbox_unittest.cc
new file mode 100644
index 0000000..c1acca6
--- /dev/null
+++ b/libchrome/sandbox/linux/services/namespace_sandbox_unittest.cc
@@ -0,0 +1,241 @@
+// 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 "sandbox/linux/services/namespace_sandbox.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "base/test/multiprocess_test.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/namespace_utils.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace sandbox {
+
+namespace {
+
+bool RootDirectoryIsEmpty() {
+  base::FilePath root("/");
+  int file_type =
+      base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES;
+  base::FileEnumerator enumerator_before(root, false, file_type);
+  return enumerator_before.Next().empty();
+}
+
+class NamespaceSandboxTest : public base::MultiProcessTest {
+ public:
+  void TestProc(const std::string& procname) {
+    TestProcWithOptions(procname, NamespaceSandbox::Options());
+  }
+
+  void TestProcWithOptions(
+      const std::string& procname,
+      const NamespaceSandbox::Options& ns_sandbox_options) {
+    if (!Credentials::CanCreateProcessInNewUserNS()) {
+      return;
+    }
+
+    base::FileHandleMappingVector fds_to_remap = {
+        std::make_pair(STDOUT_FILENO, STDOUT_FILENO),
+        std::make_pair(STDERR_FILENO, STDERR_FILENO),
+    };
+    base::LaunchOptions launch_options;
+    launch_options.fds_to_remap = &fds_to_remap;
+
+    base::Process process = NamespaceSandbox::LaunchProcessWithOptions(
+        MakeCmdLine(procname), launch_options, ns_sandbox_options);
+    ASSERT_TRUE(process.IsValid());
+
+    const int kDummyExitCode = 42;
+    int exit_code = kDummyExitCode;
+    EXPECT_TRUE(process.WaitForExit(&exit_code));
+    EXPECT_EQ(0, exit_code);
+  }
+};
+
+MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
+  const bool in_user_ns = NamespaceSandbox::InNewUserNamespace();
+  const bool in_pid_ns = NamespaceSandbox::InNewPidNamespace();
+  const bool in_net_ns = NamespaceSandbox::InNewNetNamespace();
+  CHECK(in_user_ns);
+  CHECK_EQ(in_pid_ns,
+           NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWPID));
+  CHECK_EQ(in_net_ns,
+           NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWNET));
+  if (in_pid_ns) {
+    CHECK_EQ(1, getpid());
+  }
+  return 0;
+}
+
+TEST_F(NamespaceSandboxTest, BasicUsage) {
+  TestProc("SimpleChildProcess");
+}
+
+MULTIPROCESS_TEST_MAIN(PidNsOnlyChildProcess) {
+  const bool in_user_ns = NamespaceSandbox::InNewUserNamespace();
+  const bool in_pid_ns = NamespaceSandbox::InNewPidNamespace();
+  const bool in_net_ns = NamespaceSandbox::InNewNetNamespace();
+  CHECK(in_user_ns);
+  CHECK_EQ(in_pid_ns,
+           NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWPID));
+  CHECK(!in_net_ns);
+  if (in_pid_ns) {
+    CHECK_EQ(1, getpid());
+  }
+  return 0;
+}
+
+
+TEST_F(NamespaceSandboxTest, BasicUsageWithOptions) {
+  NamespaceSandbox::Options options;
+  options.ns_types = CLONE_NEWUSER | CLONE_NEWPID;
+  TestProcWithOptions("PidNsOnlyChildProcess", options);
+}
+
+MULTIPROCESS_TEST_MAIN(ChrootMe) {
+  CHECK(!RootDirectoryIsEmpty());
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  CHECK(sandbox::Credentials::DropFileSystemAccess(ProcUtil::OpenProc().get()));
+  CHECK(RootDirectoryIsEmpty());
+  return 0;
+}
+
+// Temporarily disabled on ASAN due to crbug.com/451603.
+TEST_F(NamespaceSandboxTest, DISABLE_ON_ASAN(ChrootAndDropCapabilities)) {
+  TestProc("ChrootMe");
+}
+
+MULTIPROCESS_TEST_MAIN(NestedNamespaceSandbox) {
+  base::FileHandleMappingVector fds_to_remap = {
+      std::make_pair(STDOUT_FILENO, STDOUT_FILENO),
+      std::make_pair(STDERR_FILENO, STDERR_FILENO),
+  };
+  base::LaunchOptions launch_options;
+  launch_options.fds_to_remap = &fds_to_remap;
+  base::Process process = NamespaceSandbox::LaunchProcess(
+      base::CommandLine(base::FilePath("/bin/true")), launch_options);
+  CHECK(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  CHECK(process.WaitForExit(&exit_code));
+  CHECK_EQ(0, exit_code);
+  return 0;
+}
+
+TEST_F(NamespaceSandboxTest, NestedNamespaceSandbox) {
+  TestProc("NestedNamespaceSandbox");
+}
+
+const int kNormalExitCode = 0;
+
+// Ensure that CHECK(false) is distinguishable from _exit(kNormalExitCode).
+// Allowing noise since CHECK(false) will write a stack trace to stderr.
+SANDBOX_TEST_ALLOW_NOISE(ForkInNewPidNamespace, CheckDoesNotReturnZero) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
+      /*drop_capabilities_in_child=*/true);
+  CHECK_GE(pid, 0);
+
+  if (pid == 0) {
+    CHECK(false);
+    _exit(kNormalExitCode);
+  }
+
+  int status;
+  PCHECK(waitpid(pid, &status, 0) == pid);
+  if (WIFEXITED(status)) {
+    CHECK_NE(kNormalExitCode, WEXITSTATUS(status));
+  }
+}
+
+SANDBOX_TEST(ForkInNewPidNamespace, BasicUsage) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
+      /*drop_capabilities_in_child=*/true);
+  CHECK_GE(pid, 0);
+
+  if (pid == 0) {
+    CHECK_EQ(1, getpid());
+    CHECK(!Credentials::HasAnyCapability());
+    _exit(kNormalExitCode);
+  }
+
+  int status;
+  PCHECK(waitpid(pid, &status, 0) == pid);
+  CHECK(WIFEXITED(status));
+  CHECK_EQ(kNormalExitCode, WEXITSTATUS(status));
+}
+
+SANDBOX_TEST(ForkInNewPidNamespace, ExitWithSignal) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  CHECK(sandbox::Credentials::MoveToNewUserNS());
+  const pid_t pid = NamespaceSandbox::ForkInNewPidNamespace(
+      /*drop_capabilities_in_child=*/true);
+  CHECK_GE(pid, 0);
+
+  if (pid == 0) {
+    CHECK_EQ(1, getpid());
+    CHECK(!Credentials::HasAnyCapability());
+    CHECK(NamespaceSandbox::InstallTerminationSignalHandler(
+        SIGTERM, NamespaceSandbox::SignalExitCode(SIGTERM)));
+    while (true) {
+      raise(SIGTERM);
+    }
+  }
+
+  int status;
+  PCHECK(waitpid(pid, &status, 0) == pid);
+  CHECK(WIFEXITED(status));
+  CHECK_EQ(NamespaceSandbox::SignalExitCode(SIGTERM), WEXITSTATUS(status));
+}
+
+volatile sig_atomic_t signal_handler_called;
+void ExitSuccessfully(int sig) {
+  signal_handler_called = 1;
+}
+
+SANDBOX_TEST(InstallTerminationSignalHandler, DoesNotOverrideExistingHandlers) {
+  struct sigaction action = {};
+  action.sa_handler = &ExitSuccessfully;
+  PCHECK(sigaction(SIGUSR1, &action, nullptr) == 0);
+
+  NamespaceSandbox::InstallDefaultTerminationSignalHandlers();
+  CHECK(!NamespaceSandbox::InstallTerminationSignalHandler(
+            SIGUSR1, NamespaceSandbox::SignalExitCode(SIGUSR1)));
+
+  raise(SIGUSR1);
+  CHECK_EQ(1, signal_handler_called);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/namespace_utils.cc b/libchrome/sandbox/linux/services/namespace_utils.cc
new file mode 100644
index 0000000..97add26
--- /dev/null
+++ b/libchrome/sandbox/linux/services/namespace_utils.cc
@@ -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.
+
+#include "sandbox/linux/services/namespace_utils.h"
+
+#include <fcntl.h>
+#include <sched.h>
+#include <stddef.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/files/file_path.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/launch.h"
+#include "base/strings/safe_sprintf.h"
+#include "base/third_party/valgrind/valgrind.h"
+
+namespace sandbox {
+
+namespace {
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+const char kProcSelfSetgroups[] = "/proc/self/setgroups";
+}  // namespace
+
+// static
+bool NamespaceUtils::WriteToIdMapFile(const char* map_file, generic_id_t id) {
+  // This function needs to be async-signal-safe, as it may be called in between
+  // fork and exec.
+
+  int fd = HANDLE_EINTR(open(map_file, O_WRONLY));
+  if (fd == -1) {
+    return false;
+  }
+
+  const generic_id_t inside_id = id;
+  const generic_id_t outside_id = id;
+
+  char mapping[64];
+  const ssize_t len =
+      base::strings::SafeSPrintf(mapping, "%d %d 1\n", inside_id, outside_id);
+  const ssize_t rc = HANDLE_EINTR(write(fd, mapping, len));
+  RAW_CHECK(IGNORE_EINTR(close(fd)) == 0);
+  return rc == len;
+}
+
+// static
+bool NamespaceUtils::KernelSupportsUnprivilegedNamespace(int type) {
+  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
+  // so always consider namespaces unsupported there.
+  if (IsRunningOnValgrind()) {
+    return false;
+  }
+
+  // As of Linux 3.8, /proc/self/ns/* files exist for all namespace types. Since
+  // user namespaces were added in 3.8, it is OK to rely on the existence of
+  // /proc/self/ns/*.
+  if (!base::PathExists(base::FilePath("/proc/self/ns/user"))) {
+    return false;
+  }
+
+  const char* path;
+  switch (type) {
+    case CLONE_NEWUSER:
+      return true;
+    case CLONE_NEWIPC:
+      path = "/proc/self/ns/ipc";
+      break;
+    case CLONE_NEWNET:
+      path = "/proc/self/ns/net";
+      break;
+    case CLONE_NEWNS:
+      path = "/proc/self/ns/mnt";
+      break;
+    case CLONE_NEWPID:
+      path = "/proc/self/ns/pid";
+      break;
+    case CLONE_NEWUTS:
+      path = "/proc/self/ns/uts";
+      break;
+    default:
+      NOTREACHED();
+      return false;
+  }
+
+  return base::PathExists(base::FilePath(path));
+}
+
+// static
+bool NamespaceUtils::KernelSupportsDenySetgroups() {
+  return base::PathExists(base::FilePath(kProcSelfSetgroups));
+}
+
+// static
+bool NamespaceUtils::DenySetgroups() {
+  // This function needs to be async-signal-safe.
+  int fd = HANDLE_EINTR(open(kProcSelfSetgroups, O_WRONLY));
+  if (fd == -1) {
+    return false;
+  }
+
+  static const char kDeny[] = "deny";
+  const ssize_t len = sizeof(kDeny) - 1;
+  const ssize_t rc = HANDLE_EINTR(write(fd, kDeny, len));
+  RAW_CHECK(IGNORE_EINTR(close(fd)) == 0);
+  return rc == len;
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/namespace_utils.h b/libchrome/sandbox/linux/services/namespace_utils.h
new file mode 100644
index 0000000..ec5d241
--- /dev/null
+++ b/libchrome/sandbox/linux/services/namespace_utils.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SERVICES_NAMESPACE_UTILS_H_
+#define SANDBOX_LINUX_SERVICES_NAMESPACE_UTILS_H_
+
+#include <sys/types.h>
+
+#include <type_traits>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Utility functions for using Linux namepaces.
+class SANDBOX_EXPORT NamespaceUtils {
+ public:
+  static_assert(std::is_same<uid_t, gid_t>::value,
+                "uid_t and gid_t must be the same type");
+  // generic_id_t can be used for either uid_t or gid_t.
+  typedef uid_t generic_id_t;
+
+  // Write a uid or gid mapping from |id| to |id| in |map_file|. This function
+  // is async-signal-safe.
+  static bool WriteToIdMapFile(const char* map_file,
+                               generic_id_t id) WARN_UNUSED_RESULT;
+
+  // Returns true if unprivileged namespaces of type |type| is supported
+  // (meaning that both CLONE_NEWUSER and type are are supported).  |type| must
+  // be one of CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID,
+  // CLONE_NEWUSER, or CLONE_NEWUTS. This relies on access to /proc, so it will
+  // not work from within a sandbox.
+  static bool KernelSupportsUnprivilegedNamespace(int type);
+
+  // Returns true if the kernel supports denying setgroups in a user namespace.
+  // On kernels where this is supported, DenySetgroups must be called before a
+  // gid mapping can be added.
+  static bool KernelSupportsDenySetgroups();
+
+  // Disables setgroups() within the current user namespace. On Linux 3.18.2 and
+  // later, this is required in order to write to /proc/self/gid_map without
+  // having CAP_SETGID. Callers can determine whether is this needed with
+  // KernelSupportsDenySetgroups. This function is async-signal-safe.
+  static bool DenySetgroups() WARN_UNUSED_RESULT;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceUtils);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_NAMESPACE_UTILS_H_
diff --git a/libchrome/sandbox/linux/services/namespace_utils_unittest.cc b/libchrome/sandbox/linux/services/namespace_utils_unittest.cc
new file mode 100644
index 0000000..41ed7e8
--- /dev/null
+++ b/libchrome/sandbox/linux/services/namespace_utils_unittest.cc
@@ -0,0 +1,72 @@
+// 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 "sandbox/linux/services/namespace_utils.h"
+
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/launch.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+SANDBOX_TEST(NamespaceUtils, KernelSupportsUnprivilegedNamespace) {
+  const bool can_create_user_ns = Credentials::CanCreateProcessInNewUserNS();
+  const bool supports_user_ns =
+      NamespaceUtils::KernelSupportsUnprivilegedNamespace(CLONE_NEWUSER);
+  // can_create_user_ns implies supports_user_ns, but the converse is not
+  // necessarily true, as creating a user namespace can fail for various
+  // reasons.
+  if (can_create_user_ns) {
+    SANDBOX_ASSERT(supports_user_ns);
+  }
+}
+
+SANDBOX_TEST(NamespaceUtils, WriteToIdMapFile) {
+  if (!Credentials::CanCreateProcessInNewUserNS()) {
+    return;
+  }
+
+  const uid_t uid = getuid();
+  const gid_t gid = getgid();
+
+  const bool supports_deny_setgroups =
+      NamespaceUtils::KernelSupportsDenySetgroups();
+
+  const pid_t pid =
+      base::ForkWithFlags(CLONE_NEWUSER | SIGCHLD, nullptr, nullptr);
+  ASSERT_NE(-1, pid);
+  if (pid == 0) {
+    if (supports_deny_setgroups) {
+      RAW_CHECK(NamespaceUtils::DenySetgroups());
+    }
+
+    RAW_CHECK(getuid() != uid);
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/uid_map", uid));
+    RAW_CHECK(getuid() == uid);
+
+    RAW_CHECK(getgid() != gid);
+    RAW_CHECK(NamespaceUtils::WriteToIdMapFile("/proc/self/gid_map", gid));
+    RAW_CHECK(getgid() == gid);
+
+    _exit(0);
+  }
+
+  int status = 42;
+  SANDBOX_ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+  SANDBOX_ASSERT_EQ(0, status);
+}
+
+}  // namespace.
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/services/proc_util.cc b/libchrome/sandbox/linux/services/proc_util.cc
new file mode 100644
index 0000000..b6d58de
--- /dev/null
+++ b/libchrome/sandbox/linux/services/proc_util.cc
@@ -0,0 +1,120 @@
+// 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 "sandbox/linux/services/proc_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace sandbox {
+namespace {
+
+struct DIRCloser {
+  void operator()(DIR* d) const {
+    DCHECK(d);
+    PCHECK(0 == closedir(d));
+  }
+};
+
+typedef std::unique_ptr<DIR, DIRCloser> ScopedDIR;
+
+base::ScopedFD OpenDirectory(const char* path) {
+  DCHECK(path);
+  base::ScopedFD directory_fd(
+      HANDLE_EINTR(open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
+  PCHECK(directory_fd.is_valid());
+  return directory_fd;
+}
+
+}  // namespace
+
+int ProcUtil::CountOpenFds(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  int proc_self_fd = HANDLE_EINTR(
+      openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC));
+  PCHECK(0 <= proc_self_fd);
+
+  // Ownership of proc_self_fd is transferred here, it must not be closed
+  // or modified afterwards except via dir.
+  ScopedDIR dir(fdopendir(proc_self_fd));
+  CHECK(dir);
+
+  int count = 0;
+  struct dirent e;
+  struct dirent* de;
+  while (!readdir_r(dir.get(), &e, &de) && de) {
+    if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
+      continue;
+    }
+
+    int fd_num;
+    CHECK(base::StringToInt(e.d_name, &fd_num));
+    if (fd_num == proc_fd || fd_num == proc_self_fd) {
+      continue;
+    }
+
+    ++count;
+  }
+  return count;
+}
+
+bool ProcUtil::HasOpenDirectory(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  int proc_self_fd =
+      openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+
+  PCHECK(0 <= proc_self_fd);
+
+  // Ownership of proc_self_fd is transferred here, it must not be closed
+  // or modified afterwards except via dir.
+  ScopedDIR dir(fdopendir(proc_self_fd));
+  CHECK(dir);
+
+  struct dirent e;
+  struct dirent* de;
+  while (!readdir_r(dir.get(), &e, &de) && de) {
+    if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
+      continue;
+    }
+
+    int fd_num;
+    CHECK(base::StringToInt(e.d_name, &fd_num));
+    if (fd_num == proc_fd || fd_num == proc_self_fd) {
+      continue;
+    }
+
+    struct stat s;
+    // It's OK to use proc_self_fd here, fstatat won't modify it.
+    CHECK(fstatat(proc_self_fd, e.d_name, &s, 0) == 0);
+    if (S_ISDIR(s.st_mode)) {
+      return true;
+    }
+  }
+
+  // No open unmanaged directories found.
+  return false;
+}
+
+bool ProcUtil::HasOpenDirectory() {
+  base::ScopedFD proc_fd(
+      HANDLE_EINTR(open("/proc/", O_DIRECTORY | O_RDONLY | O_CLOEXEC)));
+  return HasOpenDirectory(proc_fd.get());
+}
+
+// static
+base::ScopedFD ProcUtil::OpenProc() {
+  return OpenDirectory("/proc/");
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/proc_util.h b/libchrome/sandbox/linux/services/proc_util.h
new file mode 100644
index 0000000..bc14c5e
--- /dev/null
+++ b/libchrome/sandbox/linux/services/proc_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 SANDBOX_LINUX_SERVICES_PROC_UTIL_H_
+#define SANDBOX_LINUX_SERVICES_PROC_UTIL_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+class SANDBOX_EXPORT ProcUtil {
+ public:
+  // Returns the number of file descriptors in the current process's FD
+  // table, excluding |proc_fd|, which should be a file descriptor for
+  // /proc/.
+  static int CountOpenFds(int proc_fd);
+
+  // Checks whether the current process has any directory file descriptor open.
+  // Directory file descriptors are "capabilities" that would let a process use
+  // system calls such as openat() to bypass restrictions such as
+  // DropFileSystemAccess().
+  // Sometimes it's useful to call HasOpenDirectory() after file system access
+  // has been dropped. In this case, |proc_fd| should be a file descriptor to
+  // /proc/. The file descriptor in |proc_fd| will be ignored by
+  // HasOpenDirectory() and remains owned by the caller. It is very important
+  // for the caller to close it.
+  static bool HasOpenDirectory(int proc_fd) WARN_UNUSED_RESULT;
+  static bool HasOpenDirectory() WARN_UNUSED_RESULT;
+
+  // Open /proc/ or crash if not possible.
+  static base::ScopedFD OpenProc();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ProcUtil);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_PROC_UTIL_H_
diff --git a/libchrome/sandbox/linux/services/proc_util_unittest.cc b/libchrome/sandbox/linux/services/proc_util_unittest.cc
new file mode 100644
index 0000000..bf25151
--- /dev/null
+++ b/libchrome/sandbox/linux/services/proc_util_unittest.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 "sandbox/linux/services/proc_util.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/files/scoped_file.h"
+#include "base/posix/eintr_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+TEST(ProcUtil, CountOpenFds) {
+  base::ScopedFD proc_fd(open("/proc/", O_RDONLY | O_DIRECTORY));
+  ASSERT_TRUE(proc_fd.is_valid());
+  int fd_count = ProcUtil::CountOpenFds(proc_fd.get());
+  int fd = open("/dev/null", O_RDONLY);
+  ASSERT_LE(0, fd);
+  EXPECT_EQ(fd_count + 1, ProcUtil::CountOpenFds(proc_fd.get()));
+  ASSERT_EQ(0, IGNORE_EINTR(close(fd)));
+  EXPECT_EQ(fd_count, ProcUtil::CountOpenFds(proc_fd.get()));
+}
+
+TEST(ProcUtil, HasOpenDirectory) {
+  // No open directory should exist at startup.
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory());
+  {
+    // Have a "/proc" file descriptor around.
+    int proc_fd = open("/proc/", O_RDONLY | O_DIRECTORY);
+    base::ScopedFD proc_fd_closer(proc_fd);
+    EXPECT_TRUE(ProcUtil::HasOpenDirectory());
+  }
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory());
+}
+
+TEST(ProcUtil, HasOpenDirectoryWithFD) {
+  int proc_fd = open("/proc/", O_RDONLY | O_DIRECTORY);
+  base::ScopedFD proc_fd_closer(proc_fd);
+  ASSERT_LE(0, proc_fd);
+
+  // Don't pass |proc_fd|, an open directory (proc_fd) should
+  // be detected.
+  EXPECT_TRUE(ProcUtil::HasOpenDirectory());
+  // Pass |proc_fd| and no open directory should be detected.
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory(proc_fd));
+
+  {
+    // Have a directory file descriptor around.
+    int open_directory_fd = open("/proc/self/", O_RDONLY | O_DIRECTORY);
+    base::ScopedFD open_directory_fd_closer(open_directory_fd);
+    EXPECT_TRUE(ProcUtil::HasOpenDirectory(proc_fd));
+  }
+
+  // The "/proc/" file descriptor should now be closed, |proc_fd| is the
+  // only directory file descriptor open.
+  EXPECT_FALSE(ProcUtil::HasOpenDirectory(proc_fd));
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/resource_limits.cc b/libchrome/sandbox/linux/services/resource_limits.cc
new file mode 100644
index 0000000..1ec1129
--- /dev/null
+++ b/libchrome/sandbox/linux/services/resource_limits.cc
@@ -0,0 +1,26 @@
+// 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 "sandbox/linux/services/resource_limits.h"
+
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include <algorithm>
+
+namespace sandbox {
+
+// static
+bool ResourceLimits::Lower(int resource, rlim_t limit) {
+  struct rlimit old_rlimit;
+  if (getrlimit(resource, &old_rlimit))
+    return false;
+  // Make sure we don't raise the existing limit.
+  const struct rlimit new_rlimit = {std::min(old_rlimit.rlim_cur, limit),
+                                    std::min(old_rlimit.rlim_max, limit)};
+  int rc = setrlimit(resource, &new_rlimit);
+  return rc == 0;
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/resource_limits.h b/libchrome/sandbox/linux/services/resource_limits.h
new file mode 100644
index 0000000..3464dab
--- /dev/null
+++ b/libchrome/sandbox/linux/services/resource_limits.h
@@ -0,0 +1,29 @@
+// 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 SANDBOX_LINUX_SERVICES_RESOURCE_LIMITS_H_
+#define SANDBOX_LINUX_SERVICES_RESOURCE_LIMITS_H_
+
+#include <sys/resource.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This class provides a small wrapper around setrlimit().
+class SANDBOX_EXPORT ResourceLimits {
+ public:
+  // Lower the soft and hard limit of |resource| to |limit|. If the current
+  // limit is lower than |limit|, keep it.
+  static bool Lower(int resource, rlim_t limit) WARN_UNUSED_RESULT;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceLimits);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_RESOURCE_LIMITS_H_
diff --git a/libchrome/sandbox/linux/services/resource_limits_unittests.cc b/libchrome/sandbox/linux/services/resource_limits_unittests.cc
new file mode 100644
index 0000000..910c740
--- /dev/null
+++ b/libchrome/sandbox/linux/services/resource_limits_unittests.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 "sandbox/linux/services/resource_limits.h"
+
+#include <errno.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+// Fails on Android: crbug.com/459158
+#if !defined(OS_ANDROID)
+#define MAYBE_NoFork DISABLE_ON_ASAN(NoFork)
+#else
+#define MAYBE_NoFork DISABLED_NoFork
+#endif  // OS_ANDROID
+
+// Not being able to fork breaks LeakSanitizer, so disable on
+// all ASAN builds.
+SANDBOX_TEST(ResourceLimits, MAYBE_NoFork) {
+  // Make sure that fork will fail with EAGAIN.
+  SANDBOX_ASSERT(ResourceLimits::Lower(RLIMIT_NPROC, 0));
+  errno = 0;
+  pid_t pid = fork();
+  // Reap any child if fork succeeded.
+  TestUtils::HandlePostForkReturn(pid);
+  SANDBOX_ASSERT_EQ(-1, pid);
+  CHECK_EQ(EAGAIN, errno);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/scoped_process.cc b/libchrome/sandbox/linux/services/scoped_process.cc
new file mode 100644
index 0000000..65af487
--- /dev/null
+++ b/libchrome/sandbox/linux/services/scoped_process.cc
@@ -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.
+
+#include "sandbox/linux/services/scoped_process.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+
+namespace sandbox {
+
+namespace {
+
+const char kSynchronisationChar[] = "D";
+
+void WaitForever() {
+  while(true) {
+    pause();
+  }
+}
+
+}  // namespace
+
+ScopedProcess::ScopedProcess(const base::Closure& child_callback)
+    : child_process_id_(-1), process_id_(getpid()) {
+  PCHECK(0 == pipe(pipe_fds_));
+#if !defined(THREAD_SANITIZER)
+  // Make sure that we can safely fork().
+  CHECK(ThreadHelpers::IsSingleThreaded());
+#endif
+  child_process_id_ = fork();
+  PCHECK(0 <= child_process_id_);
+
+  if (0 == child_process_id_) {
+    PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0])));
+    pipe_fds_[0] = -1;
+    child_callback.Run();
+    // Notify the parent that the closure has run.
+    CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds_[1], kSynchronisationChar, 1)));
+    WaitForever();
+    NOTREACHED();
+    _exit(1);
+  }
+
+  PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1])));
+  pipe_fds_[1] = -1;
+}
+
+ScopedProcess::~ScopedProcess() {
+  CHECK(IsOriginalProcess());
+  if (child_process_id_ >= 0) {
+    PCHECK(0 == kill(child_process_id_, SIGKILL));
+    siginfo_t process_info;
+
+    PCHECK(0 == HANDLE_EINTR(
+                    waitid(P_PID, child_process_id_, &process_info, WEXITED)));
+  }
+  if (pipe_fds_[0] >= 0) {
+    PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[0])));
+  }
+  if (pipe_fds_[1] >= 0) {
+    PCHECK(0 == IGNORE_EINTR(close(pipe_fds_[1])));
+  }
+}
+
+int ScopedProcess::WaitForExit(bool* got_signaled) {
+  DCHECK(got_signaled);
+  CHECK(IsOriginalProcess());
+  siginfo_t process_info;
+  // WNOWAIT to make sure that the destructor can wait on the child.
+  int ret = HANDLE_EINTR(
+      waitid(P_PID, child_process_id_, &process_info, WEXITED | WNOWAIT));
+  PCHECK(0 == ret) << "Did something else wait on the child?";
+
+  if (process_info.si_code == CLD_EXITED) {
+    *got_signaled = false;
+  } else if (process_info.si_code == CLD_KILLED ||
+             process_info.si_code == CLD_DUMPED) {
+    *got_signaled = true;
+  } else {
+    CHECK(false) << "ScopedProcess needs to be extended for si_code "
+                 << process_info.si_code;
+  }
+  return process_info.si_status;
+}
+
+bool ScopedProcess::WaitForClosureToRun() {
+  char c = 0;
+  int ret = HANDLE_EINTR(read(pipe_fds_[0], &c, 1));
+  PCHECK(ret >= 0);
+  if (0 == ret)
+    return false;
+
+  CHECK_EQ(c, kSynchronisationChar[0]);
+  return true;
+}
+
+// It would be problematic if after a fork(), another process would start using
+// this object.
+// This method allows to assert it is not happening.
+bool ScopedProcess::IsOriginalProcess() {
+  // Make a direct syscall to bypass glibc caching of PIDs.
+  pid_t pid = sys_getpid();
+  return pid == process_id_;
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/scoped_process.h b/libchrome/sandbox/linux/services/scoped_process.h
new file mode 100644
index 0000000..bddbd55
--- /dev/null
+++ b/libchrome/sandbox/linux/services/scoped_process.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SERVICES_SCOPED_PROCESS_H_
+#define SANDBOX_LINUX_SERVICES_SCOPED_PROCESS_H_
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// fork() a child process that will run a Closure.
+// After the Closure has run, the child will pause forever. If this object
+// is detroyed, the child will be destroyed, even if the closure did not
+// finish running. It's ok to signal the child from outside of this class to
+// destroy it.
+// This class cannot be instanciated from a multi-threaded process, as it needs
+// to fork().
+class SANDBOX_EXPORT ScopedProcess {
+ public:
+  // A new process will be created and |child_callback| will run in the child
+  // process. This callback is allowed to terminate the process or to simply
+  // return. If the callback returns, the process will wait forever.
+  explicit ScopedProcess(const base::Closure& child_callback);
+  ~ScopedProcess();
+
+  // Wait for the process to exit.
+  // |got_signaled| tells how to interpret the return value: either as an exit
+  // code, or as a signal number.
+  // When this returns, the process will still not have been reaped and will
+  // survive as a zombie for the lifetime of this object. This method can be
+  // called multiple times.
+  int WaitForExit(bool* got_signaled);
+
+  // Wait for the |child_callback| passed at construction to run. Return false
+  // if |child_callback| did not finish running and we know it never will (for
+  // instance the child crashed or used _exit()).
+  bool WaitForClosureToRun();
+  base::ProcessId GetPid() { return child_process_id_; }
+
+ private:
+  bool IsOriginalProcess();
+
+  base::ProcessId child_process_id_;
+  base::ProcessId process_id_;
+  int pipe_fds_[2];
+  DISALLOW_COPY_AND_ASSIGN(ScopedProcess);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_SCOPED_PROCESS_H_
diff --git a/libchrome/sandbox/linux/services/scoped_process_unittest.cc b/libchrome/sandbox/linux/services/scoped_process_unittest.cc
new file mode 100644
index 0000000..86f97a8
--- /dev/null
+++ b/libchrome/sandbox/linux/services/scoped_process_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 "sandbox/linux/services/scoped_process.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.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/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+void DoExit() { _exit(0); }
+
+void ExitWithCode(int exit_code) { _exit(exit_code); }
+
+void RaiseAndExit(int signal) {
+  PCHECK(0 == raise(signal));
+  _exit(0);
+}
+
+TEST(ScopedProcess, ScopedProcessNormalExit) {
+  const int kCustomExitCode = 12;
+  ScopedProcess process(base::Bind(&ExitWithCode, kCustomExitCode));
+  bool got_signaled = true;
+  int exit_code = process.WaitForExit(&got_signaled);
+  EXPECT_FALSE(got_signaled);
+  EXPECT_EQ(kCustomExitCode, exit_code);
+
+  // Verify that WaitForExit() can be called multiple times on the same
+  // process.
+  bool got_signaled2 = true;
+  int exit_code2 = process.WaitForExit(&got_signaled2);
+  EXPECT_FALSE(got_signaled2);
+  EXPECT_EQ(kCustomExitCode, exit_code2);
+}
+
+// Disable this test on Android, SIGABRT is funky there.
+TEST(ScopedProcess, DISABLE_ON_ANDROID(ScopedProcessAbort)) {
+  PCHECK(SIG_ERR != signal(SIGABRT, SIG_DFL));
+  ScopedProcess process(base::Bind(&RaiseAndExit, SIGABRT));
+  bool got_signaled = false;
+  int exit_code = process.WaitForExit(&got_signaled);
+  EXPECT_TRUE(got_signaled);
+  EXPECT_EQ(SIGABRT, exit_code);
+}
+
+TEST(ScopedProcess, ScopedProcessSignaled) {
+  ScopedProcess process(base::Bind(&base::DoNothing));
+  bool got_signaled = false;
+  ASSERT_EQ(0, kill(process.GetPid(), SIGKILL));
+  int exit_code = process.WaitForExit(&got_signaled);
+  EXPECT_TRUE(got_signaled);
+  EXPECT_EQ(SIGKILL, exit_code);
+}
+
+TEST(ScopedProcess, DiesForReal) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+  base::ScopedFD read_end_closer(pipe_fds[0]);
+  base::ScopedFD write_end_closer(pipe_fds[1]);
+
+  { ScopedProcess process(base::Bind(&DoExit)); }
+
+  // Close writing end of the pipe.
+  write_end_closer.reset();
+  pipe_fds[1] = -1;
+
+  ASSERT_EQ(0, fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK));
+  char c;
+  // If the child process is dead for real, there will be no writing end
+  // for this pipe left and read will EOF instead of returning EWOULDBLOCK.
+  ASSERT_EQ(0, read(pipe_fds[0], &c, 1));
+}
+
+TEST(ScopedProcess, SynchronizationBasic) {
+  ScopedProcess process1(base::Bind(&base::DoNothing));
+  EXPECT_TRUE(process1.WaitForClosureToRun());
+
+  ScopedProcess process2(base::Bind(&DoExit));
+  // The closure didn't finish running normally. This case is simple enough
+  // that process.WaitForClosureToRun() should return false, even though the
+  // API does not guarantees that it will return at all.
+  EXPECT_FALSE(process2.WaitForClosureToRun());
+}
+
+void SleepInMsAndWriteOneByte(int time_to_sleep, int fd) {
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(time_to_sleep));
+  CHECK(1 == write(fd, "1", 1));
+}
+
+TEST(ScopedProcess, SynchronizationWorks) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+  base::ScopedFD read_end_closer(pipe_fds[0]);
+  base::ScopedFD write_end_closer(pipe_fds[1]);
+
+  // Start a process with a closure that takes a little bit to run.
+  ScopedProcess process(
+      base::Bind(&SleepInMsAndWriteOneByte, 100, pipe_fds[1]));
+  EXPECT_TRUE(process.WaitForClosureToRun());
+
+  // Verify that the closure did, indeed, run.
+  ASSERT_EQ(0, fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK));
+  char c = 0;
+  EXPECT_EQ(1, read(pipe_fds[0], &c, 1));
+  EXPECT_EQ('1', c);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/syscall_wrappers.cc b/libchrome/sandbox/linux/services/syscall_wrappers.cc
new file mode 100644
index 0000000..7132d2a
--- /dev/null
+++ b/libchrome/sandbox/linux/services/syscall_wrappers.cc
@@ -0,0 +1,261 @@
+// 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 "sandbox/linux/services/syscall_wrappers.h"
+
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cstring>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+pid_t sys_getpid(void) {
+  return syscall(__NR_getpid);
+}
+
+pid_t sys_gettid(void) {
+  return syscall(__NR_gettid);
+}
+
+long sys_clone(unsigned long flags,
+               std::nullptr_t child_stack,
+               pid_t* ptid,
+               pid_t* ctid,
+               std::nullptr_t tls) {
+  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 sys_clone");
+  }
+
+  if (ptid) MSAN_UNPOISON(ptid, sizeof(*ptid));
+  if (ctid) MSAN_UNPOISON(ctid, sizeof(*ctid));
+  // 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, child_stack, ptid, ctid, tls);
+#elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \
+    defined(ARCH_CPU_MIPS_FAMILY)
+  // CONFIG_CLONE_BACKWARDS defined.
+  return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid);
+#endif
+}
+
+long sys_clone(unsigned long flags) {
+  return sys_clone(flags, nullptr, nullptr, nullptr, nullptr);
+}
+
+void sys_exit_group(int status) {
+  syscall(__NR_exit_group, status);
+}
+
+int sys_seccomp(unsigned int operation,
+                unsigned int flags,
+                const struct sock_fprog* args) {
+  return syscall(__NR_seccomp, operation, flags, args);
+}
+
+int sys_prlimit64(pid_t pid,
+                  int resource,
+                  const struct rlimit64* new_limit,
+                  struct rlimit64* old_limit) {
+  int res = syscall(__NR_prlimit64, pid, resource, new_limit, old_limit);
+  if (res == 0 && old_limit) MSAN_UNPOISON(old_limit, sizeof(*old_limit));
+  return res;
+}
+
+int sys_capget(cap_hdr* hdrp, cap_data* datap) {
+  int res = syscall(__NR_capget, hdrp, datap);
+  if (res == 0) {
+    if (hdrp) MSAN_UNPOISON(hdrp, sizeof(*hdrp));
+    if (datap) MSAN_UNPOISON(datap, sizeof(*datap));
+  }
+  return res;
+}
+
+int sys_capset(cap_hdr* hdrp, const cap_data* datap) {
+  return syscall(__NR_capset, hdrp, datap);
+}
+
+int sys_getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) {
+  int res;
+#if defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARMEL)
+  // On 32-bit x86 or 32-bit arm, getresuid supports 16bit values only.
+  // Use getresuid32 instead.
+  res = syscall(__NR_getresuid32, ruid, euid, suid);
+#else
+  res = syscall(__NR_getresuid, ruid, euid, suid);
+#endif
+  if (res == 0) {
+    if (ruid) MSAN_UNPOISON(ruid, sizeof(*ruid));
+    if (euid) MSAN_UNPOISON(euid, sizeof(*euid));
+    if (suid) MSAN_UNPOISON(suid, sizeof(*suid));
+  }
+  return res;
+}
+
+int sys_getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid) {
+  int res;
+#if defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARMEL)
+  // On 32-bit x86 or 32-bit arm, getresgid supports 16bit values only.
+  // Use getresgid32 instead.
+  res = syscall(__NR_getresgid32, rgid, egid, sgid);
+#else
+  res = syscall(__NR_getresgid, rgid, egid, sgid);
+#endif
+  if (res == 0) {
+    if (rgid) MSAN_UNPOISON(rgid, sizeof(*rgid));
+    if (egid) MSAN_UNPOISON(egid, sizeof(*egid));
+    if (sgid) MSAN_UNPOISON(sgid, sizeof(*sgid));
+  }
+  return res;
+}
+
+int sys_chroot(const char* path) {
+  return syscall(__NR_chroot, path);
+}
+
+int sys_unshare(int flags) {
+  return syscall(__NR_unshare, flags);
+}
+
+int sys_sigprocmask(int how, const sigset_t* set, std::nullptr_t oldset) {
+  // In some toolchain (in particular Android and PNaCl toolchain),
+  // sigset_t is 32 bits, but the Linux ABI uses more.
+  LinuxSigSet linux_value;
+  std::memset(&linux_value, 0, sizeof(LinuxSigSet));
+  std::memcpy(&linux_value, set, std::min(sizeof(sigset_t),
+                                          sizeof(LinuxSigSet)));
+
+  return syscall(__NR_rt_sigprocmask, how, &linux_value, nullptr,
+                 sizeof(linux_value));
+}
+
+// When this is built with PNaCl toolchain, we should always use sys_sigaction
+// below, because sigaction() provided by the toolchain is incompatible with
+// Linux's ABI.
+#if !defined(OS_NACL_NONSFI)
+int sys_sigaction(int signum,
+                  const struct sigaction* act,
+                  struct sigaction* oldact) {
+  return sigaction(signum, act, oldact);
+}
+#else
+#if defined(ARCH_CPU_X86_FAMILY)
+
+// On x86_64, sa_restorer is required. We specify it on x86 as well in order to
+// support kernels with VDSO disabled.
+#if !defined(SA_RESTORER)
+#define SA_RESTORER 0x04000000
+#endif
+
+// XSTR(__NR_foo) expands to a string literal containing the value value of
+// __NR_foo.
+#define STR(x) #x
+#define XSTR(x) STR(x)
+
+// rt_sigreturn is a special system call that interacts with the user land
+// stack. Thus, here prologue must not be created, which implies syscall()
+// does not work properly, too. Note that rt_sigreturn does not return.
+// TODO(rickyz): These assembly functions may still break stack unwinding on
+// nonsfi NaCl builds.
+#if defined(ARCH_CPU_X86_64)
+
+extern "C" {
+  void sys_rt_sigreturn();
+}
+
+asm(
+    ".text\n"
+    "sys_rt_sigreturn:\n"
+    "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
+    "syscall\n");
+
+#elif defined(ARCH_CPU_X86)
+extern "C" {
+  void sys_sigreturn();
+  void sys_rt_sigreturn();
+}
+
+asm(
+    ".text\n"
+    "sys_rt_sigreturn:\n"
+    "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
+    "int $0x80\n"
+
+    "sys_sigreturn:\n"
+    "pop %eax\n"
+    "mov $" XSTR(__NR_sigreturn) ", %eax\n"
+    "int $0x80\n");
+#else
+#error "Unsupported architecture."
+#endif
+
+#undef STR
+#undef XSTR
+
+#endif
+
+int sys_sigaction(int signum,
+                  const struct sigaction* act,
+                  struct sigaction* oldact) {
+  LinuxSigAction linux_act = {};
+  if (act) {
+    linux_act.kernel_handler = act->sa_handler;
+    std::memcpy(&linux_act.sa_mask, &act->sa_mask,
+                std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
+    linux_act.sa_flags = act->sa_flags;
+
+#if defined(ARCH_CPU_X86_FAMILY)
+    if (!(linux_act.sa_flags & SA_RESTORER)) {
+      linux_act.sa_flags |= SA_RESTORER;
+#if defined(ARCH_CPU_X86_64)
+      linux_act.sa_restorer = sys_rt_sigreturn;
+#elif defined(ARCH_CPU_X86)
+      linux_act.sa_restorer =
+          linux_act.sa_flags & SA_SIGINFO ? sys_rt_sigreturn : sys_sigreturn;
+#else
+#error "Unsupported architecture."
+#endif
+    }
+#endif
+  }
+
+  LinuxSigAction linux_oldact = {};
+  int result = syscall(__NR_rt_sigaction, signum, act ? &linux_act : nullptr,
+                       oldact ? &linux_oldact : nullptr,
+                       sizeof(LinuxSigSet));
+
+  if (result == 0 && oldact) {
+    oldact->sa_handler = linux_oldact.kernel_handler;
+    sigemptyset(&oldact->sa_mask);
+    std::memcpy(&oldact->sa_mask, &linux_oldact.sa_mask,
+                std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
+    oldact->sa_flags = linux_oldact.sa_flags;
+  }
+  return result;
+}
+
+#endif  // defined(MEMORY_SANITIZER)
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/syscall_wrappers.h b/libchrome/sandbox/linux/services/syscall_wrappers.h
new file mode 100644
index 0000000..057e4c8
--- /dev/null
+++ b/libchrome/sandbox/linux/services/syscall_wrappers.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
+#define SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
+
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cstddef>
+
+#include "sandbox/sandbox_export.h"
+
+struct sock_fprog;
+struct rlimit64;
+struct cap_hdr;
+struct cap_data;
+
+namespace sandbox {
+
+// Provide direct system call wrappers for a few common system calls.
+// These are guaranteed to perform a system call and do not rely on things such
+// as caching the current pid (c.f. getpid()) unless otherwise specified.
+
+SANDBOX_EXPORT pid_t sys_getpid(void);
+
+SANDBOX_EXPORT pid_t sys_gettid(void);
+
+SANDBOX_EXPORT long sys_clone(unsigned long flags);
+
+// |regs| is not supported and must be passed as nullptr. |child_stack| must be
+// nullptr, since otherwise this function cannot safely return. As a
+// consequence, this function does not support CLONE_VM.
+SANDBOX_EXPORT long sys_clone(unsigned long flags,
+                              std::nullptr_t child_stack,
+                              pid_t* ptid,
+                              pid_t* ctid,
+                              std::nullptr_t regs);
+
+SANDBOX_EXPORT void sys_exit_group(int status);
+
+// The official system call takes |args| as void*  (in order to be extensible),
+// but add more typing for the cases that are currently used.
+SANDBOX_EXPORT int sys_seccomp(unsigned int operation,
+                               unsigned int flags,
+                               const struct sock_fprog* args);
+
+// Some libcs do not expose a prlimit64 wrapper.
+SANDBOX_EXPORT int sys_prlimit64(pid_t pid,
+                                 int resource,
+                                 const struct rlimit64* new_limit,
+                                 struct rlimit64* old_limit);
+
+// Some libcs do not expose capget/capset wrappers. We want to use these
+// directly in order to avoid pulling in libcap2.
+SANDBOX_EXPORT int sys_capget(struct cap_hdr* hdrp, struct cap_data* datap);
+SANDBOX_EXPORT int sys_capset(struct cap_hdr* hdrp,
+                              const struct cap_data* datap);
+
+// Some libcs do not expose getresuid/getresgid wrappers.
+SANDBOX_EXPORT int sys_getresuid(uid_t* ruid, uid_t* euid, uid_t* suid);
+SANDBOX_EXPORT int sys_getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid);
+
+// Some libcs do not expose a chroot wrapper.
+SANDBOX_EXPORT int sys_chroot(const char* path);
+
+// Some libcs do not expose a unshare wrapper.
+SANDBOX_EXPORT int sys_unshare(int flags);
+
+// Some libcs do not expose a sigprocmask. Note that oldset must be a nullptr,
+// because of some ABI gap between toolchain's and Linux's.
+SANDBOX_EXPORT int sys_sigprocmask(int how,
+                                   const sigset_t* set,
+                                   std::nullptr_t oldset);
+
+// Some libcs do not expose a sigaction().
+SANDBOX_EXPORT int sys_sigaction(int signum,
+                                 const struct sigaction* act,
+                                 struct sigaction* oldact);
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
diff --git a/libchrome/sandbox/linux/services/syscall_wrappers_unittest.cc b/libchrome/sandbox/linux/services/syscall_wrappers_unittest.cc
new file mode 100644
index 0000000..34ac740
--- /dev/null
+++ b/libchrome/sandbox/linux/services/syscall_wrappers_unittest.cc
@@ -0,0 +1,100 @@
+// 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 "sandbox/linux/services/syscall_wrappers.h"
+
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <cstring>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+TEST(SyscallWrappers, BasicSyscalls) {
+  EXPECT_EQ(getpid(), sys_getpid());
+}
+
+TEST(SyscallWrappers, CloneBasic) {
+  pid_t child = sys_clone(SIGCHLD);
+  TestUtils::HandlePostForkReturn(child);
+  EXPECT_LT(0, child);
+}
+
+TEST(SyscallWrappers, CloneParentSettid) {
+  pid_t ptid = 0;
+  pid_t child = sys_clone(CLONE_PARENT_SETTID | SIGCHLD, nullptr, &ptid,
+                          nullptr, nullptr);
+  TestUtils::HandlePostForkReturn(child);
+  EXPECT_LT(0, child);
+  EXPECT_EQ(child, ptid);
+}
+
+TEST(SyscallWrappers, CloneChildSettid) {
+  pid_t ctid = 0;
+  pid_t pid =
+      sys_clone(CLONE_CHILD_SETTID | SIGCHLD, nullptr, nullptr, &ctid, nullptr);
+
+  const int kSuccessExit = 0;
+  if (0 == pid) {
+    // In child.
+    if (sys_getpid() == ctid)
+      _exit(kSuccessExit);
+    _exit(1);
+  }
+
+  ASSERT_NE(-1, pid);
+  int status = 0;
+  ASSERT_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
+  ASSERT_TRUE(WIFEXITED(status));
+  EXPECT_EQ(kSuccessExit, WEXITSTATUS(status));
+}
+
+TEST(SyscallWrappers, GetRESUid) {
+  uid_t ruid, euid, suid;
+  uid_t sys_ruid, sys_euid, sys_suid;
+  ASSERT_EQ(0, getresuid(&ruid, &euid, &suid));
+  ASSERT_EQ(0, sys_getresuid(&sys_ruid, &sys_euid, &sys_suid));
+  EXPECT_EQ(ruid, sys_ruid);
+  EXPECT_EQ(euid, sys_euid);
+  EXPECT_EQ(suid, sys_suid);
+}
+
+TEST(SyscallWrappers, GetRESGid) {
+  gid_t rgid, egid, sgid;
+  gid_t sys_rgid, sys_egid, sys_sgid;
+  ASSERT_EQ(0, getresgid(&rgid, &egid, &sgid));
+  ASSERT_EQ(0, sys_getresgid(&sys_rgid, &sys_egid, &sys_sgid));
+  EXPECT_EQ(rgid, sys_rgid);
+  EXPECT_EQ(egid, sys_egid);
+  EXPECT_EQ(sgid, sys_sgid);
+}
+
+TEST(SyscallWrappers, LinuxSigSet) {
+  sigset_t sigset;
+  ASSERT_EQ(0, sigemptyset(&sigset));
+  ASSERT_EQ(0, sigaddset(&sigset, LINUX_SIGSEGV));
+  ASSERT_EQ(0, sigaddset(&sigset, LINUX_SIGBUS));
+  uint64_t linux_sigset = 0;
+  std::memcpy(&linux_sigset, &sigset,
+              std::min(sizeof(sigset), sizeof(linux_sigset)));
+  EXPECT_EQ((1ULL << (LINUX_SIGSEGV - 1)) | (1ULL << (LINUX_SIGBUS - 1)),
+            linux_sigset);
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/thread_helpers.cc b/libchrome/sandbox/linux/services/thread_helpers.cc
new file mode 100644
index 0000000..20752c8
--- /dev/null
+++ b/libchrome/sandbox/linux/services/thread_helpers.cc
@@ -0,0 +1,200 @@
+// 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 "sandbox/linux/services/thread_helpers.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "sandbox/linux/services/proc_util.h"
+
+namespace sandbox {
+
+namespace {
+
+const char kAssertSingleThreadedError[] =
+    "Current process is not mono-threaded!";
+const char kAssertThreadDoesNotAppearInProcFS[] =
+    "Started thread does not appear in /proc";
+const char kAssertThreadDoesNotDisappearInProcFS[] =
+    "Stopped thread does not disappear in /proc";
+
+bool IsSingleThreadedImpl(int proc_fd) {
+  CHECK_LE(0, proc_fd);
+  struct stat task_stat;
+  int fstat_ret = fstatat(proc_fd, "self/task/", &task_stat, 0);
+  PCHECK(0 == fstat_ret);
+
+  // At least "..", "." and the current thread should be present.
+  CHECK_LE(3UL, task_stat.st_nlink);
+  // Counting threads via /proc/self/task could be racy. For the purpose of
+  // determining if the current proces is monothreaded it works: if at any
+  // time it becomes monothreaded, it'll stay so.
+  return task_stat.st_nlink == 3;
+}
+
+bool IsThreadPresentInProcFS(int proc_fd,
+                             const std::string& thread_id_dir_str) {
+  struct stat task_stat;
+  const int fstat_ret =
+      fstatat(proc_fd, thread_id_dir_str.c_str(), &task_stat, 0);
+  if (fstat_ret < 0) {
+    PCHECK(ENOENT == errno);
+    return false;
+  }
+  return true;
+}
+
+bool IsNotThreadPresentInProcFS(int proc_fd,
+                                const std::string& thread_id_dir_str) {
+  return !IsThreadPresentInProcFS(proc_fd, thread_id_dir_str);
+}
+
+// Run |cb| in a loop until it returns false. Every time |cb| runs, sleep
+// for an exponentially increasing amount of time. |cb| is expected to return
+// false very quickly and this will crash if it doesn't happen within ~64ms on
+// Debug builds (2s on Release builds).
+// This is guaranteed to not sleep more than twice as much as the bare minimum
+// amount of time.
+void RunWhileTrue(const base::Callback<bool(void)>& cb, const char* message) {
+#if defined(NDEBUG)
+  // In Release mode, crash after 30 iterations, which means having spent
+  // roughly 2s in
+  // nanosleep(2) cumulatively.
+  const unsigned int kMaxIterations = 30U;
+#else
+  // In practice, this never goes through more than a couple iterations. In
+  // debug mode, crash after 64ms (+ eventually 25 times the granularity of
+  // the clock) in nanosleep(2). This ensures that this is not becoming too
+  // slow.
+  const unsigned int kMaxIterations = 25U;
+#endif
+
+  // Run |cb| with an exponential back-off, sleeping 2^iterations nanoseconds
+  // in nanosleep(2).
+  // Note: the clock may not allow for nanosecond granularity, in this case the
+  // first iterations would sleep a tiny bit more instead, which would not
+  // change the calculations significantly.
+  for (unsigned int i = 0; i < kMaxIterations; ++i) {
+    if (!cb.Run()) {
+      return;
+    }
+
+    // Increase the waiting time exponentially.
+    struct timespec ts = {0, 1L << i /* nanoseconds */};
+    PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts)));
+  }
+
+  LOG(FATAL) << message << " (iterations: " << kMaxIterations << ")";
+
+  NOTREACHED();
+}
+
+bool IsMultiThreaded(int proc_fd) {
+  return !ThreadHelpers::IsSingleThreaded(proc_fd);
+}
+
+enum class ThreadAction { Start, Stop };
+
+bool ChangeThreadStateAndWatchProcFS(
+    int proc_fd, base::Thread* thread, ThreadAction action) {
+  DCHECK_LE(0, proc_fd);
+  DCHECK(thread);
+  DCHECK(action == ThreadAction::Start || action == ThreadAction::Stop);
+
+  base::Callback<bool(void)> cb;
+  const char* message;
+
+  if (action == ThreadAction::Start) {
+    // Should start the thread before calling thread_id().
+    if (!thread->Start())
+      return false;
+  }
+
+  const base::PlatformThreadId thread_id = thread->GetThreadId();
+  const std::string thread_id_dir_str =
+      "self/task/" + base::IntToString(thread_id) + "/";
+
+  if (action == ThreadAction::Stop) {
+    // The target thread should exist in /proc.
+    DCHECK(IsThreadPresentInProcFS(proc_fd, thread_id_dir_str));
+    thread->Stop();
+  }
+
+  // The kernel is at liberty to wake the thread id futex before updating
+  // /proc. Start() above or following Stop(), the thread is started or joined,
+  // but entries in /proc may not have been updated.
+  if (action == ThreadAction::Start) {
+    cb = base::Bind(&IsNotThreadPresentInProcFS, proc_fd, thread_id_dir_str);
+    message = kAssertThreadDoesNotAppearInProcFS;
+  } else {
+    cb = base::Bind(&IsThreadPresentInProcFS, proc_fd, thread_id_dir_str);
+    message = kAssertThreadDoesNotDisappearInProcFS;
+  }
+  RunWhileTrue(cb, message);
+
+  DCHECK_EQ(action == ThreadAction::Start,
+            IsThreadPresentInProcFS(proc_fd, thread_id_dir_str));
+
+  return true;
+}
+
+}  // namespace
+
+// static
+bool ThreadHelpers::IsSingleThreaded(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  return IsSingleThreadedImpl(proc_fd);
+}
+
+// static
+bool ThreadHelpers::IsSingleThreaded() {
+  base::ScopedFD task_fd(ProcUtil::OpenProc());
+  return IsSingleThreaded(task_fd.get());
+}
+
+// static
+void ThreadHelpers::AssertSingleThreaded(int proc_fd) {
+  DCHECK_LE(0, proc_fd);
+  const base::Callback<bool(void)> cb = base::Bind(&IsMultiThreaded, proc_fd);
+  RunWhileTrue(cb, kAssertSingleThreadedError);
+}
+
+void ThreadHelpers::AssertSingleThreaded() {
+  base::ScopedFD task_fd(ProcUtil::OpenProc());
+  AssertSingleThreaded(task_fd.get());
+}
+
+// static
+bool ThreadHelpers::StartThreadAndWatchProcFS(int proc_fd,
+                                              base::Thread* thread) {
+  return ChangeThreadStateAndWatchProcFS(proc_fd, thread, ThreadAction::Start);
+}
+
+// static
+bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_fd,
+                                             base::Thread* thread) {
+  return ChangeThreadStateAndWatchProcFS(proc_fd, thread, ThreadAction::Stop);
+}
+
+// static
+const char* ThreadHelpers::GetAssertSingleThreadedErrorMessageForTests() {
+  return kAssertSingleThreadedError;
+}
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/thread_helpers.h b/libchrome/sandbox/linux/services/thread_helpers.h
new file mode 100644
index 0000000..73e041a
--- /dev/null
+++ b/libchrome/sandbox/linux/services/thread_helpers.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.
+
+#ifndef SANDBOX_LINUX_SERVICES_THREAD_HELPERS_H_
+#define SANDBOX_LINUX_SERVICES_THREAD_HELPERS_H_
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace base { class Thread; }
+
+namespace sandbox {
+
+class SANDBOX_EXPORT ThreadHelpers {
+ public:
+  // Checks whether the current process is single threaded. |proc_fd|
+  // must be a file descriptor to /proc/ and remains owned by the
+  // caller.
+  static bool IsSingleThreaded(int proc_fd);
+  static bool IsSingleThreaded();
+
+  // Crashes if the current process is not single threaded. This will wait
+  // on /proc to be updated. In the case where this doesn't crash, this will
+  // return promptly. In the case where this does crash, this will first wait
+  // for a few ms in Debug mode, a few seconds in Release mode.
+  static void AssertSingleThreaded(int proc_fd);
+  static void AssertSingleThreaded();
+
+  // Starts |thread| and ensure that it has an entry in /proc/self/task/ from
+  // the point of view of the current thread.
+  static bool StartThreadAndWatchProcFS(int proc_fd, base::Thread* thread);
+
+  // Stops |thread| and ensure that it does not have an entry in
+  // /proc/self/task/ from the point of view of the current thread. This is
+  // the way to stop threads before calling IsSingleThreaded().
+  static bool StopThreadAndWatchProcFS(int proc_fd, base::Thread* thread);
+
+  static const char* GetAssertSingleThreadedErrorMessageForTests();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadHelpers);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_THREAD_HELPERS_H_
diff --git a/libchrome/sandbox/linux/services/thread_helpers_unittests.cc b/libchrome/sandbox/linux/services/thread_helpers_unittests.cc
new file mode 100644
index 0000000..fe1080b
--- /dev/null
+++ b/libchrome/sandbox/linux/services/thread_helpers_unittests.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 "sandbox/linux/services/thread_helpers.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::PlatformThread;
+
+namespace sandbox {
+
+namespace {
+
+// These tests fail under ThreadSanitizer, see http://crbug.com/342305
+#if !defined(THREAD_SANITIZER)
+
+int GetRaceTestIterations() {
+  if (IsRunningOnValgrind()) {
+    return 2;
+  } else {
+    return 1000;
+  }
+}
+
+class ScopedProc {
+ public:
+  ScopedProc() : fd_(-1) {
+    fd_ = open("/proc/", O_RDONLY | O_DIRECTORY);
+    CHECK_LE(0, fd_);
+  }
+
+  ~ScopedProc() { PCHECK(0 == IGNORE_EINTR(close(fd_))); }
+
+  int fd() { return fd_; }
+
+ private:
+  int fd_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedProc);
+};
+
+TEST(ThreadHelpers, IsSingleThreadedBasic) {
+  ScopedProc proc_fd;
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded());
+
+  base::Thread thread("sandbox_tests");
+  ASSERT_TRUE(ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
+  ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+  ASSERT_FALSE(ThreadHelpers::IsSingleThreaded());
+  // Explicitly stop the thread here to not pollute the next test.
+  ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
+}
+
+SANDBOX_TEST(ThreadHelpers, AssertSingleThreaded) {
+  ScopedProc proc_fd;
+  SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+  SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded());
+
+  ThreadHelpers::AssertSingleThreaded(proc_fd.fd());
+  ThreadHelpers::AssertSingleThreaded();
+}
+
+TEST(ThreadHelpers, IsSingleThreadedIterated) {
+  ScopedProc proc_fd;
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+
+  // Iterate to check for race conditions.
+  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+    base::Thread thread("sandbox_tests");
+    ASSERT_TRUE(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
+    ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+    // Explicitly stop the thread here to not pollute the next test.
+    ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
+  }
+}
+
+TEST(ThreadHelpers, IsSingleThreadedStartAndStop) {
+  ScopedProc proc_fd;
+  ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+
+  base::Thread thread("sandbox_tests");
+  // This is testing for a race condition, so iterate.
+  // Manually, this has been tested with more that 1M iterations.
+  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+    ASSERT_TRUE(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
+    ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+
+    ASSERT_TRUE(ThreadHelpers::StopThreadAndWatchProcFS(proc_fd.fd(), &thread));
+    ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
+    ASSERT_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
+  }
+}
+
+SANDBOX_TEST(ThreadHelpers, AssertSingleThreadedAfterThreadStopped) {
+  ScopedProc proc_fd;
+  SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded());
+
+  base::Thread thread1("sandbox_tests");
+  base::Thread thread2("sandbox_tests");
+
+  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+    SANDBOX_ASSERT(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread1));
+    SANDBOX_ASSERT(
+        ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread2));
+    SANDBOX_ASSERT(!ThreadHelpers::IsSingleThreaded());
+
+    thread1.Stop();
+    thread2.Stop();
+    // This will wait on /proc/ to reflect the state of threads in the
+    // process.
+    ThreadHelpers::AssertSingleThreaded();
+    SANDBOX_ASSERT(ThreadHelpers::IsSingleThreaded());
+  }
+}
+
+// Only run this test in Debug mode, where AssertSingleThreaded() will return
+// in less than 64ms.
+#if !defined(NDEBUG)
+SANDBOX_DEATH_TEST(
+    ThreadHelpers,
+    AssertSingleThreadedDies,
+    DEATH_MESSAGE(
+        ThreadHelpers::GetAssertSingleThreadedErrorMessageForTests())) {
+  base::Thread thread1("sandbox_tests");
+  SANDBOX_ASSERT(thread1.Start());
+  ThreadHelpers::AssertSingleThreaded();
+}
+#endif  // !defined(NDEBUG)
+
+#endif  // !defined(THREAD_SANITIZER)
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/yama.cc b/libchrome/sandbox/linux/services/yama.cc
new file mode 100644
index 0000000..6831cd9
--- /dev/null
+++ b/libchrome/sandbox/linux/services/yama.cc
@@ -0,0 +1,117 @@
+// 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 "sandbox/linux/services/yama.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <sys/prctl.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/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+#if !defined(PR_SET_PTRACER_ANY)
+#define PR_SET_PTRACER_ANY ((unsigned long)-1)
+#endif
+
+#if !defined(PR_SET_PTRACER)
+#define PR_SET_PTRACER 0x59616d61
+#endif
+
+namespace sandbox {
+
+namespace {
+
+// Enable or disable the Yama ptracers restrictions.
+// Return false if Yama is not present on this kernel.
+bool SetYamaPtracersRestriction(bool enable_restrictions) {
+  unsigned long set_ptracer_arg;
+  if (enable_restrictions) {
+    set_ptracer_arg = 0;
+  } else {
+    set_ptracer_arg = PR_SET_PTRACER_ANY;
+  }
+
+  const int ret = prctl(PR_SET_PTRACER, set_ptracer_arg);
+  const int prctl_errno = errno;
+
+  if (0 == ret) {
+    return true;
+  } else {
+    // ENOSYS or EINVAL means Yama is not in the current kernel.
+    CHECK(ENOSYS == prctl_errno || EINVAL == prctl_errno);
+    return false;
+  }
+}
+
+bool CanAccessProcFS() {
+  static const char kProcfsKernelSysPath[] = "/proc/sys/kernel/";
+  int ret = access(kProcfsKernelSysPath, F_OK);
+  if (ret) {
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+// static
+bool Yama::RestrictPtracersToAncestors() {
+  return SetYamaPtracersRestriction(true /* enable_restrictions */);
+}
+
+// static
+bool Yama::DisableYamaRestrictions() {
+  return SetYamaPtracersRestriction(false /* enable_restrictions */);
+}
+
+// static
+int Yama::GetStatus() {
+  if (!CanAccessProcFS()) {
+    return 0;
+  }
+
+  static const char kPtraceScopePath[] = "/proc/sys/kernel/yama/ptrace_scope";
+
+  base::ScopedFD yama_scope(HANDLE_EINTR(open(kPtraceScopePath, O_RDONLY)));
+
+  if (!yama_scope.is_valid()) {
+    const int open_errno = errno;
+    DCHECK(ENOENT == open_errno);
+    // The status is known, yama is not present.
+    return STATUS_KNOWN;
+  }
+
+  char yama_scope_value = 0;
+  ssize_t num_read = HANDLE_EINTR(read(yama_scope.get(), &yama_scope_value, 1));
+  PCHECK(1 == num_read);
+
+  switch (yama_scope_value) {
+    case '0':
+      return STATUS_KNOWN | STATUS_PRESENT;
+    case '1':
+      return STATUS_KNOWN | STATUS_PRESENT | STATUS_ENFORCING;
+    case '2':
+    case '3':
+      return STATUS_KNOWN | STATUS_PRESENT | STATUS_ENFORCING |
+             STATUS_STRICT_ENFORCING;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+// static
+bool Yama::IsPresent() { return GetStatus() & STATUS_PRESENT; }
+
+// static
+bool Yama::IsEnforcing() { return GetStatus() & STATUS_ENFORCING; }
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/services/yama.h b/libchrome/sandbox/linux/services/yama.h
new file mode 100644
index 0000000..e6c5c45
--- /dev/null
+++ b/libchrome/sandbox/linux/services/yama.h
@@ -0,0 +1,57 @@
+// 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 SANDBOX_LINUX_SERVICES_YAMA_H_
+#define SANDBOX_LINUX_SERVICES_YAMA_H_
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Yama is a LSM kernel module which can restrict ptrace().
+// This class provides ways to detect if Yama is present and enabled
+// and to restrict which processes can ptrace the current process.
+class SANDBOX_EXPORT Yama {
+ public:
+  // This enum should be used to set or check a bitmask.
+  // A value of 0 would indicate that the status is not known.
+  enum GlobalStatus {
+    STATUS_KNOWN = 1 << 0,
+    STATUS_PRESENT = 1 << 1,
+    STATUS_ENFORCING = 1 << 2,
+    // STATUS_STRICT_ENFORCING corresponds to either mode 2 or mode 3 of Yama.
+    // Ptrace could be entirely denied, or restricted to CAP_SYS_PTRACE
+    // and PTRACE_TRACEME.
+    STATUS_STRICT_ENFORCING = 1 << 3
+  };
+
+  // Restrict who can ptrace() the current process to its ancestors.
+  // If this succeeds, then Yama is available on this kernel.
+  // However, Yama may not be enforcing at this time.
+  static bool RestrictPtracersToAncestors();
+
+  // Disable Yama restrictions for the current process.
+  // This will fail if Yama is not available on this kernel.
+  // This is meant for testing only. If you need this, implement
+  // a per-pid authorization instead.
+  static bool DisableYamaRestrictions();
+
+  // Checks if Yama is currently in enforcing mode for the machine (not the
+  // current process). This requires access to the filesystem and will use
+  // /proc/sys/kernel/yama/ptrace_scope.
+  static int GetStatus();
+
+  // Helper for checking for STATUS_PRESENT in GetStatus().
+  static bool IsPresent();
+  // Helper for checkking for STATUS_ENFORCING in GetStatus().
+  static bool IsEnforcing();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Yama);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_YAMA_H_
diff --git a/libchrome/sandbox/linux/services/yama_unittests.cc b/libchrome/sandbox/linux/services/yama_unittests.cc
new file mode 100644
index 0000000..0e8355d
--- /dev/null
+++ b/libchrome/sandbox/linux/services/yama_unittests.cc
@@ -0,0 +1,172 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "sandbox/linux/services/scoped_process.h"
+#include "sandbox/linux/services/yama.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+bool HasLinux32Bug() {
+#if defined(__i386__)
+  // On 3.2 kernels, yama doesn't work for 32-bit binaries on 64-bit kernels.
+  // This is fixed in 3.4.
+  bool is_kernel_64bit =
+      base::SysInfo::OperatingSystemArchitecture() == "x86_64";
+  bool is_linux = base::SysInfo::OperatingSystemName() == "Linux";
+  bool is_3_dot_2 = base::StartsWith(
+      base::SysInfo::OperatingSystemVersion(), "3.2",
+      base::CompareCase::INSENSITIVE_ASCII);
+  if (is_kernel_64bit && is_linux && is_3_dot_2)
+    return true;
+#endif  // defined(__i386__)
+  return false;
+}
+
+bool CanPtrace(pid_t pid) {
+  int ret;
+  ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
+  if (ret == -1) {
+    CHECK_EQ(EPERM, errno);
+    return false;
+  }
+  // Wait for the process to be stopped so that it can be detached.
+  siginfo_t process_info;
+  int wait_ret = HANDLE_EINTR(waitid(P_PID, pid, &process_info, WSTOPPED));
+  PCHECK(0 == wait_ret);
+  PCHECK(0 == ptrace(PTRACE_DETACH, pid, NULL, NULL));
+  return true;
+}
+
+// _exit(0) if pid can be ptraced by the current process.
+// _exit(1) otherwise.
+void ExitZeroIfCanPtrace(pid_t pid) {
+  if (CanPtrace(pid)) {
+    _exit(0);
+  } else {
+    _exit(1);
+  }
+}
+
+bool CanSubProcessPtrace(pid_t pid) {
+  ScopedProcess process(base::Bind(&ExitZeroIfCanPtrace, pid));
+  bool signaled;
+  int exit_code = process.WaitForExit(&signaled);
+  CHECK(!signaled);
+  return 0 == exit_code;
+}
+
+// The tests below assume that the system-level configuration will not change
+// while they run.
+
+TEST(Yama, GetStatus) {
+  int status1 = Yama::GetStatus();
+
+  // Check that the value is a possible bitmask.
+  ASSERT_LE(0, status1);
+  ASSERT_GE(Yama::STATUS_KNOWN | Yama::STATUS_PRESENT | Yama::STATUS_ENFORCING |
+                Yama::STATUS_STRICT_ENFORCING,
+            status1);
+
+  // The status should not just be a random value.
+  int status2 = Yama::GetStatus();
+  EXPECT_EQ(status1, status2);
+
+  // This test is not running sandboxed, there is no reason to not know the
+  // status.
+  EXPECT_NE(0, Yama::STATUS_KNOWN & status1);
+
+  if (status1 & Yama::STATUS_STRICT_ENFORCING) {
+    // If Yama is strictly enforcing, it is also enforcing.
+    EXPECT_TRUE(status1 & Yama::STATUS_ENFORCING);
+  }
+
+  if (status1 & Yama::STATUS_ENFORCING) {
+    // If Yama is enforcing, Yama is present.
+    EXPECT_NE(0, status1 & Yama::STATUS_PRESENT);
+  }
+
+  // Verify that the helper functions work as intended.
+  EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_ENFORCING),
+            Yama::IsEnforcing());
+  EXPECT_EQ(static_cast<bool>(status1 & Yama::STATUS_PRESENT),
+            Yama::IsPresent());
+
+  fprintf(stdout,
+          "Yama present: %s - enforcing: %s\n",
+          Yama::IsPresent() ? "Y" : "N",
+          Yama::IsEnforcing() ? "Y" : "N");
+}
+
+SANDBOX_TEST(Yama, RestrictPtraceSucceedsWhenYamaPresent) {
+  // This call will succeed iff Yama is present.
+  bool restricted = Yama::RestrictPtracersToAncestors();
+  CHECK_EQ(restricted, Yama::IsPresent());
+}
+
+// Attempts to enable or disable Yama restrictions.
+void SetYamaRestrictions(bool enable_restriction) {
+  if (enable_restriction) {
+    Yama::RestrictPtracersToAncestors();
+  } else {
+    Yama::DisableYamaRestrictions();
+  }
+}
+
+TEST(Yama, RestrictPtraceWorks) {
+  if (HasLinux32Bug())
+    return;
+
+  ScopedProcess process1(base::Bind(&SetYamaRestrictions, true));
+  ASSERT_TRUE(process1.WaitForClosureToRun());
+
+  if (Yama::IsEnforcing()) {
+    // A sibling process cannot ptrace process1.
+    ASSERT_FALSE(CanSubProcessPtrace(process1.GetPid()));
+  }
+
+  if (!(Yama::GetStatus() & Yama::STATUS_STRICT_ENFORCING)) {
+    // However, parent can ptrace process1.
+    ASSERT_TRUE(CanPtrace(process1.GetPid()));
+
+    // A sibling can ptrace process2 which disables any Yama protection.
+    ScopedProcess process2(base::Bind(&SetYamaRestrictions, false));
+    ASSERT_TRUE(process2.WaitForClosureToRun());
+    ASSERT_TRUE(CanSubProcessPtrace(process2.GetPid()));
+  }
+}
+
+SANDBOX_TEST(Yama, RestrictPtraceIsDefault) {
+  if (!Yama::IsPresent() || HasLinux32Bug())
+    return;
+
+  CHECK(Yama::DisableYamaRestrictions());
+  ScopedProcess process1(base::Bind(&base::DoNothing));
+
+  if (Yama::IsEnforcing()) {
+    // Check that process1 is protected by Yama, even though it has
+    // been created from a process that disabled Yama.
+    CHECK(!CanSubProcessPtrace(process1.GetPid()));
+  }
+}
+
+}  // namespace
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/suid/client/DEPS b/libchrome/sandbox/linux/suid/client/DEPS
new file mode 100644
index 0000000..99a337d
--- /dev/null
+++ b/libchrome/sandbox/linux/suid/client/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox/linux/services",
+]
diff --git a/libchrome/sandbox/linux/suid/common/sandbox.h b/libchrome/sandbox/linux/suid/common/sandbox.h
new file mode 100644
index 0000000..52ef10c
--- /dev/null
+++ b/libchrome/sandbox/linux/suid/common/sandbox.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 SANDBOX_LINUX_SUID_SANDBOX_H_
+#define SANDBOX_LINUX_SUID_SANDBOX_H_
+
+#if defined(__cplusplus)
+namespace sandbox {
+#endif
+
+// These are command line switches that may be used by other programs
+// (e.g. Chrome) to construct a command line for the sandbox.
+static const char kSuidSandboxGetApiSwitch[] = "--get-api";
+static const char kAdjustOOMScoreSwitch[] = "--adjust-oom-score";
+
+static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D";
+static const char kSandboxHelperPidEnvironmentVarName[] = "SBX_HELPER_PID";
+
+static const int kSUIDSandboxApiNumber = 1;
+static const char kSandboxEnvironmentApiRequest[] = "SBX_CHROME_API_RQ";
+static const char kSandboxEnvironmentApiProvides[] = "SBX_CHROME_API_PRV";
+
+// This number must be kept in sync with common/zygote_commands_linux.h
+static const int kZygoteIdFd = 7;
+
+// These are the magic byte values which the sandboxed process uses to request
+// that it be chrooted.
+static const char kMsgChrootMe = 'C';
+static const char kMsgChrootSuccessful = 'O';
+
+// These are set if we have respectively switched to a new PID or NET namespace
+// by going through the setuid binary helper.
+static const char kSandboxPIDNSEnvironmentVarName[] = "SBX_PID_NS";
+static const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS";
+
+#if defined(__cplusplus)
+}  // namespace sandbox
+#endif
+
+#endif  // SANDBOX_LINUX_SUID_SANDBOX_H_
diff --git a/libchrome/sandbox/linux/suid/common/suid_unsafe_environment_variables.h b/libchrome/sandbox/linux/suid/common/suid_unsafe_environment_variables.h
new file mode 100644
index 0000000..e955e0c
--- /dev/null
+++ b/libchrome/sandbox/linux/suid/common/suid_unsafe_environment_variables.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.
+
+// This is a list of environment variables which the ELF loader unsets when
+// loading a SUID binary. Because they are unset rather than just ignored, they
+// aren't passed to child processes of SUID processes either.
+//
+// We need to save these environment variables before running a SUID sandbox
+// and restore them before running child processes (but after dropping root).
+//
+// List gathered from glibc sources (00ebd7ed58df389a78e41dece058048725cb585e):
+//   sysdeps/unix/sysv/linux/i386/dl-librecon.h
+//   sysdeps/generic/unsecvars.h
+
+#ifndef SANDBOX_LINUX_SUID_COMMON_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+#define SANDBOX_LINUX_SUID_COMMON_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>  // malloc
+#include <string.h>  // memcpy
+
+static const char* const kSUIDUnsafeEnvironmentVariables[] = {
+  "LD_AOUT_LIBRARY_PATH",
+  "LD_AOUT_PRELOAD",
+  "GCONV_PATH",
+  "GETCONF_DIR",
+  "HOSTALIASES",
+  "LD_AUDIT",
+  "LD_DEBUG",
+  "LD_DEBUG_OUTPUT",
+  "LD_DYNAMIC_WEAK",
+  "LD_LIBRARY_PATH",
+  "LD_ORIGIN_PATH",
+  "LD_PRELOAD",
+  "LD_PROFILE",
+  "LD_SHOW_AUXV",
+  "LD_USE_LOAD_BIAS",
+  "LOCALDOMAIN",
+  "LOCPATH",
+  "MALLOC_TRACE",
+  "NIS_PATH",
+  "NLSPATH",
+  "RESOLV_HOST_CONF",
+  "RES_OPTIONS",
+  "TMPDIR",
+  "TZDIR",
+  NULL,
+};
+
+// Return a malloc allocated string containing the 'saved' environment variable
+// name for a given environment variable.
+static inline char* SandboxSavedEnvironmentVariable(const char* envvar) {
+  const size_t envvar_len = strlen(envvar);
+  const size_t kMaxSizeT = (size_t) -1;
+
+  if (envvar_len > kMaxSizeT - 1 - 8)
+    return NULL;
+
+  const size_t saved_envvarlen = envvar_len + 1 /* NUL terminator */ +
+                                              8 /* strlen("SANDBOX_") */;
+  char* const saved_envvar = (char*) malloc(saved_envvarlen);
+  if (!saved_envvar)
+    return NULL;
+
+  memcpy(saved_envvar, "SANDBOX_", 8);
+  memcpy(saved_envvar + 8, envvar, envvar_len);
+  saved_envvar[8 + envvar_len] = 0;
+
+  return saved_envvar;
+}
+
+#endif  // SANDBOX_LINUX_SUID_COMMON_SUID_UNSAFE_ENVIRONMENT_VARIABLES_H_
diff --git a/libchrome/sandbox/linux/suid/process_util.h b/libchrome/sandbox/linux/suid/process_util.h
new file mode 100644
index 0000000..10071d3
--- /dev/null
+++ b/libchrome/sandbox/linux/suid/process_util.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.
+
+// The following is duplicated from base/process_utils.h.
+// We shouldn't link against C++ code in a setuid binary.
+
+#ifndef SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
+#define SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+// This adjusts /proc/process/oom_score_adj so the Linux OOM killer
+// will prefer certain process types over others. The range for the
+// adjustment is [-1000, 1000], with [0, 1000] being user accessible.
+//
+// If the Linux system isn't new enough to use oom_score_adj, then we
+// try to set the older oom_adj value instead, scaling the score to
+// the required range of [0, 15]. This may result in some aliasing of
+// values, of course.
+bool AdjustOOMScore(pid_t process, int score);
+
+// This adjusts /sys/kernel/mm/chromeos-low_mem/margin so that
+// the kernel notifies us that we are low on memory when less than
+// |margin_mb| megabytes are available.  Setting |margin_mb| to -1
+// turns off low memory notification.
+bool AdjustLowMemoryMargin(int64_t margin_mb);
+
+#endif  // SANDBOX_LINUX_SUID_PROCESS_UTIL_H_
diff --git a/libchrome/sandbox/linux/suid/process_util_linux.c b/libchrome/sandbox/linux/suid/process_util_linux.c
new file mode 100644
index 0000000..40949bd
--- /dev/null
+++ b/libchrome/sandbox/linux/suid/process_util_linux.c
@@ -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.
+
+// The following is the C version of code from base/process_utils_linux.cc.
+// We shouldn't link against C++ code in a setuid binary.
+
+// Needed for O_DIRECTORY, must be defined before fcntl.h is included
+// (and it can be included earlier than the explicit #include below
+// in some versions of glibc).
+#define _GNU_SOURCE
+
+#include "sandbox/linux/suid/process_util.h"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// Ranges for the current (oom_score_adj) and previous (oom_adj)
+// flavors of OOM score.
+static const int kMaxOomScore = 1000;
+static const int kMaxOldOomScore = 15;
+
+// NOTE: This is not the only version of this function in the source:
+// the base library (in process_util_linux.cc) also has its own C++ version.
+bool AdjustOOMScore(pid_t process, int score) {
+  if (score < 0 || score > kMaxOomScore)
+    return false;
+
+  char oom_adj[27];  // "/proc/" + log_10(2**64) + "\0"
+                     //    6     +       20     +     1         = 27
+  snprintf(oom_adj, sizeof(oom_adj), "/proc/%" PRIdMAX, (intmax_t)process);
+
+  const int dirfd = open(oom_adj, O_RDONLY | O_DIRECTORY);
+  if (dirfd < 0)
+    return false;
+
+  struct stat statbuf;
+  if (fstat(dirfd, &statbuf) < 0) {
+    close(dirfd);
+    return false;
+  }
+  if (getuid() != statbuf.st_uid) {
+    close(dirfd);
+    return false;
+  }
+
+  int fd = openat(dirfd, "oom_score_adj", O_WRONLY);
+  if (fd < 0) {
+    // We failed to open oom_score_adj, so let's try for the older
+    // oom_adj file instead.
+    fd = openat(dirfd, "oom_adj", O_WRONLY);
+    if (fd < 0) {
+      // Nope, that doesn't work either.
+      return false;
+    } else {
+      // If we're using the old oom_adj file, the allowed range is now
+      // [0, kMaxOldOomScore], so we scale the score.  This may result in some
+      // aliasing of values, of course.
+      score = score * kMaxOldOomScore / kMaxOomScore;
+    }
+  }
+  close(dirfd);
+
+  char buf[11];  // 0 <= |score| <= kMaxOomScore; using log_10(2**32) + 1 size
+  snprintf(buf, sizeof(buf), "%d", score);
+  size_t len = strlen(buf);
+
+  ssize_t bytes_written = write(fd, buf, len);
+  close(fd);
+  return (bytes_written == (ssize_t)len);
+}
diff --git a/libchrome/sandbox/linux/suid/sandbox.c b/libchrome/sandbox/linux/suid/sandbox.c
new file mode 100644
index 0000000..b655d1c
--- /dev/null
+++ b/libchrome/sandbox/linux/suid/sandbox.c
@@ -0,0 +1,483 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox.md
+
+#include "sandbox/linux/suid/common/sandbox.h"
+
+#define _GNU_SOURCE
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "sandbox/linux/suid/common/suid_unsafe_environment_variables.h"
+#include "sandbox/linux/suid/process_util.h"
+
+#if !defined(CLONE_NEWPID)
+#define CLONE_NEWPID 0x20000000
+#endif
+#if !defined(CLONE_NEWNET)
+#define CLONE_NEWNET 0x40000000
+#endif
+
+static bool DropRoot();
+
+#define HANDLE_EINTR(x) TEMP_FAILURE_RETRY(x)
+
+static void FatalError(const char* msg, ...)
+    __attribute__((noreturn, format(printf, 1, 2)));
+
+static void FatalError(const char* msg, ...) {
+  va_list ap;
+  va_start(ap, msg);
+
+  vfprintf(stderr, msg, ap);
+  fprintf(stderr, ": %s\n", strerror(errno));
+  fflush(stderr);
+  va_end(ap);
+  _exit(1);
+}
+
+static void ExitWithErrorSignalHandler(int signal) {
+  const char msg[] = "\nThe setuid sandbox got signaled, exiting.\n";
+  if (-1 == write(2, msg, sizeof(msg) - 1)) {
+    // Do nothing.
+  }
+
+  _exit(1);
+}
+
+// We will chroot() to the helper's /proc/self directory. Anything there will
+// not exist anymore if we make sure to wait() for the helper.
+//
+// /proc/self/fdinfo or /proc/self/fd are especially safe and will be empty
+// even if the helper survives as a zombie.
+//
+// There is very little reason to use fdinfo/ instead of fd/ but we are
+// paranoid. fdinfo/ only exists since 2.6.22 so we allow fallback to fd/
+#define SAFE_DIR "/proc/self/fdinfo"
+#define SAFE_DIR2 "/proc/self/fd"
+
+static bool SpawnChrootHelper() {
+  int sv[2];
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+    perror("socketpair");
+    return false;
+  }
+
+  char* safedir = NULL;
+  struct stat sdir_stat;
+  if (!stat(SAFE_DIR, &sdir_stat) && S_ISDIR(sdir_stat.st_mode)) {
+    safedir = SAFE_DIR;
+  } else if (!stat(SAFE_DIR2, &sdir_stat) && S_ISDIR(sdir_stat.st_mode)) {
+    safedir = SAFE_DIR2;
+  } else {
+    fprintf(stderr, "Could not find %s\n", SAFE_DIR2);
+    return false;
+  }
+
+  const pid_t pid = syscall(__NR_clone, CLONE_FS | SIGCHLD, 0, 0, 0);
+
+  if (pid == -1) {
+    perror("clone");
+    close(sv[0]);
+    close(sv[1]);
+    return false;
+  }
+
+  if (pid == 0) {
+    // We share our files structure with an untrusted process. As a security in
+    // depth measure, we make sure that we can't open anything by mistake.
+    // TODO(agl): drop CAP_SYS_RESOURCE / use SECURE_NOROOT
+
+    const struct rlimit nofile = {0, 0};
+    if (setrlimit(RLIMIT_NOFILE, &nofile))
+      FatalError("Setting RLIMIT_NOFILE");
+
+    if (close(sv[1]))
+      FatalError("close");
+
+    // wait for message
+    char msg;
+    ssize_t bytes;
+    do {
+      bytes = read(sv[0], &msg, 1);
+    } while (bytes == -1 && errno == EINTR);
+
+    if (bytes == 0)
+      _exit(0);
+    if (bytes != 1)
+      FatalError("read");
+
+    // do chrooting
+    if (msg != kMsgChrootMe)
+      FatalError("Unknown message from sandboxed process");
+
+    // sanity check
+    if (chdir(safedir))
+      FatalError("Cannot chdir into /proc/ directory");
+
+    if (chroot(safedir))
+      FatalError("Cannot chroot into /proc/ directory");
+
+    if (chdir("/"))
+      FatalError("Cannot chdir to / after chroot");
+
+    const char reply = kMsgChrootSuccessful;
+    do {
+      bytes = write(sv[0], &reply, 1);
+    } while (bytes == -1 && errno == EINTR);
+
+    if (bytes != 1)
+      FatalError("Writing reply");
+
+    _exit(0);
+    // We now become a zombie. /proc/self/fd(info) is now an empty dir and we
+    // are chrooted there.
+    // Our (unprivileged) parent should not even be able to open "." or "/"
+    // since they would need to pass the ptrace() check. If our parent wait()
+    // for us, our root directory will completely disappear.
+  }
+
+  if (close(sv[0])) {
+    close(sv[1]);
+    perror("close");
+    return false;
+  }
+
+  // In the parent process, we install an environment variable containing the
+  // number of the file descriptor.
+  char desc_str[64];
+  int printed = snprintf(desc_str, sizeof(desc_str), "%u", sv[1]);
+  if (printed < 0 || printed >= (int)sizeof(desc_str)) {
+    fprintf(stderr, "Failed to snprintf\n");
+    return false;
+  }
+
+  if (setenv(kSandboxDescriptorEnvironmentVarName, desc_str, 1)) {
+    perror("setenv");
+    close(sv[1]);
+    return false;
+  }
+
+  // We also install an environment variable containing the pid of the child
+  char helper_pid_str[64];
+  printed = snprintf(helper_pid_str, sizeof(helper_pid_str), "%u", pid);
+  if (printed < 0 || printed >= (int)sizeof(helper_pid_str)) {
+    fprintf(stderr, "Failed to snprintf\n");
+    return false;
+  }
+
+  if (setenv(kSandboxHelperPidEnvironmentVarName, helper_pid_str, 1)) {
+    perror("setenv");
+    close(sv[1]);
+    return false;
+  }
+
+  return true;
+}
+
+// Block until child_pid exits, then exit. Try to preserve the exit code.
+static void WaitForChildAndExit(pid_t child_pid) {
+  int exit_code = -1;
+  siginfo_t reaped_child_info;
+
+  // Don't "Core" on SIGABRT. SIGABRT is sent by the Chrome OS session manager
+  // when things are hanging.
+  // Here, the current process is going to waitid() and _exit(), so there is no
+  // point in generating a crash report. The child process is the one
+  // blocking us.
+  if (signal(SIGABRT, ExitWithErrorSignalHandler) == SIG_ERR) {
+    FatalError("Failed to change signal handler");
+  }
+
+  int wait_ret =
+      HANDLE_EINTR(waitid(P_PID, child_pid, &reaped_child_info, WEXITED));
+
+  if (!wait_ret && reaped_child_info.si_pid == child_pid) {
+    if (reaped_child_info.si_code == CLD_EXITED) {
+      exit_code = reaped_child_info.si_status;
+    } else {
+      // Exit with code 0 if the child got signaled.
+      exit_code = 0;
+    }
+  }
+  _exit(exit_code);
+}
+
+static bool MoveToNewNamespaces() {
+  // These are the sets of flags which we'll try, in order.
+  const int kCloneExtraFlags[] = {CLONE_NEWPID | CLONE_NEWNET, CLONE_NEWPID, };
+
+  // We need to close kZygoteIdFd before the child can continue. We use this
+  // socketpair to tell the child when to continue;
+  int sync_fds[2];
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sync_fds)) {
+    FatalError("Failed to create a socketpair");
+  }
+
+  for (size_t i = 0; i < sizeof(kCloneExtraFlags) / sizeof(kCloneExtraFlags[0]);
+       i++) {
+    pid_t pid = syscall(__NR_clone, SIGCHLD | kCloneExtraFlags[i], 0, 0, 0);
+    const int clone_errno = errno;
+
+    if (pid > 0) {
+      if (!DropRoot()) {
+        FatalError("Could not drop privileges");
+      } else {
+        if (close(sync_fds[0]) || shutdown(sync_fds[1], SHUT_RD))
+          FatalError("Could not close socketpair");
+        // The kZygoteIdFd needs to be closed in the parent before
+        // Zygote gets started.
+        if (close(kZygoteIdFd))
+          FatalError("close");
+        // Tell our child to continue
+        if (HANDLE_EINTR(send(sync_fds[1], "C", 1, MSG_NOSIGNAL)) != 1)
+          FatalError("send");
+        if (close(sync_fds[1]))
+          FatalError("close");
+        // We want to keep a full process tree and we don't want our childs to
+        // be reparented to (the outer PID namespace) init. So we wait for it.
+        WaitForChildAndExit(pid);
+      }
+      // NOTREACHED
+      FatalError("Not reached");
+    }
+
+    if (pid == 0) {
+      if (close(sync_fds[1]) || shutdown(sync_fds[0], SHUT_WR))
+        FatalError("Could not close socketpair");
+
+      // Wait for the parent to confirm it closed kZygoteIdFd before we
+      // continue
+      char should_continue;
+      if (HANDLE_EINTR(read(sync_fds[0], &should_continue, 1)) != 1)
+        FatalError("Read on socketpair");
+      if (close(sync_fds[0]))
+        FatalError("close");
+
+      if (kCloneExtraFlags[i] & CLONE_NEWPID) {
+        setenv(kSandboxPIDNSEnvironmentVarName, "", 1 /* overwrite */);
+      } else {
+        unsetenv(kSandboxPIDNSEnvironmentVarName);
+      }
+
+      if (kCloneExtraFlags[i] & CLONE_NEWNET) {
+        setenv(kSandboxNETNSEnvironmentVarName, "", 1 /* overwrite */);
+      } else {
+        unsetenv(kSandboxNETNSEnvironmentVarName);
+      }
+
+      break;
+    }
+
+    // If EINVAL then the system doesn't support the requested flags, so
+    // continue to try a different set.
+    // On any other errno value the system *does* support these flags but
+    // something went wrong, hence we bail with an error message rather then
+    // provide less security.
+    if (errno != EINVAL) {
+      fprintf(stderr, "Failed to move to new namespace:");
+      if (kCloneExtraFlags[i] & CLONE_NEWPID) {
+        fprintf(stderr, " PID namespaces supported,");
+      }
+      if (kCloneExtraFlags[i] & CLONE_NEWNET) {
+        fprintf(stderr, " Network namespace supported,");
+      }
+      fprintf(stderr, " but failed: errno = %s\n", strerror(clone_errno));
+      return false;
+    }
+  }
+
+  // If the system doesn't support NEWPID then we carry on anyway.
+  return true;
+}
+
+static bool DropRoot() {
+  if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0)) {
+    perror("prctl(PR_SET_DUMPABLE)");
+    return false;
+  }
+
+  if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
+    perror("Still dumpable after prctl(PR_SET_DUMPABLE)");
+    return false;
+  }
+
+  gid_t rgid, egid, sgid;
+  if (getresgid(&rgid, &egid, &sgid)) {
+    perror("getresgid");
+    return false;
+  }
+
+  if (setresgid(rgid, rgid, rgid)) {
+    perror("setresgid");
+    return false;
+  }
+
+  uid_t ruid, euid, suid;
+  if (getresuid(&ruid, &euid, &suid)) {
+    perror("getresuid");
+    return false;
+  }
+
+  if (setresuid(ruid, ruid, ruid)) {
+    perror("setresuid");
+    return false;
+  }
+
+  return true;
+}
+
+static bool SetupChildEnvironment() {
+  unsigned i;
+
+  // ld.so may have cleared several environment variables because we are SUID.
+  // However, the child process might need them so zygote_host_linux.cc saves a
+  // copy in SANDBOX_$x. This is safe because we have dropped root by this
+  // point, so we can only exec a binary with the permissions of the user who
+  // ran us in the first place.
+
+  for (i = 0; kSUIDUnsafeEnvironmentVariables[i]; ++i) {
+    const char* const envvar = kSUIDUnsafeEnvironmentVariables[i];
+    char* const saved_envvar = SandboxSavedEnvironmentVariable(envvar);
+    if (!saved_envvar)
+      return false;
+
+    const char* const value = getenv(saved_envvar);
+    if (value) {
+      setenv(envvar, value, 1 /* overwrite */);
+      unsetenv(saved_envvar);
+    }
+
+    free(saved_envvar);
+  }
+
+  return true;
+}
+
+bool CheckAndExportApiVersion() {
+  // Check the environment to see if a specific API version was requested.
+  // assume version 0 if none.
+  int api_number = -1;
+  char* api_string = getenv(kSandboxEnvironmentApiRequest);
+  if (!api_string) {
+    api_number = 0;
+  } else {
+    errno = 0;
+    char* endptr = NULL;
+    long long_api_number = strtol(api_string, &endptr, 10);
+    if (!endptr || *endptr || errno != 0 || long_api_number < INT_MIN ||
+        long_api_number > INT_MAX) {
+      return false;
+    }
+    api_number = long_api_number;
+  }
+
+  // Warn only for now.
+  if (api_number != kSUIDSandboxApiNumber) {
+    fprintf(
+        stderr,
+        "The setuid sandbox provides API version %d, "
+        "but you need %d\n"
+        "Please read "
+        "https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md."
+        "\n\n",
+        kSUIDSandboxApiNumber,
+        api_number);
+  }
+
+  // Export our version so that the sandboxed process can verify it did not
+  // use an old sandbox.
+  char version_string[64];
+  snprintf(version_string, sizeof(version_string), "%d", kSUIDSandboxApiNumber);
+  if (setenv(kSandboxEnvironmentApiProvides, version_string, 1)) {
+    perror("setenv");
+    return false;
+  }
+
+  return true;
+}
+
+int main(int argc, char** argv) {
+  if (argc <= 1) {
+    if (argc <= 0) {
+      return 1;
+    }
+
+    fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]);
+    return 1;
+  }
+
+  // Allow someone to query our API version
+  if (argc == 2 && 0 == strcmp(argv[1], kSuidSandboxGetApiSwitch)) {
+    printf("%d\n", kSUIDSandboxApiNumber);
+    return 0;
+  }
+
+  // We cannot adjust /proc/pid/oom_adj for sandboxed renderers
+  // because those files are owned by root. So we need a helper here.
+  if (argc == 4 && (0 == strcmp(argv[1], kAdjustOOMScoreSwitch))) {
+    char* endptr = NULL;
+    long score;
+    errno = 0;
+    unsigned long pid_ul = strtoul(argv[2], &endptr, 10);
+    if (pid_ul == ULONG_MAX || !endptr || *endptr || errno != 0)
+      return 1;
+    pid_t pid = pid_ul;
+    endptr = NULL;
+    errno = 0;
+    score = strtol(argv[3], &endptr, 10);
+    if (score == LONG_MAX || score == LONG_MIN || !endptr || *endptr ||
+        errno != 0) {
+      return 1;
+    }
+    return AdjustOOMScore(pid, score);
+  }
+
+  // Protect the core setuid sandbox functionality with an API version
+  if (!CheckAndExportApiVersion()) {
+    return 1;
+  }
+
+  if (geteuid() != 0) {
+    fprintf(stderr,
+            "The setuid sandbox is not running as root. Common causes:\n"
+            "  * An unprivileged process using ptrace on it, like a debugger.\n"
+            "  * A parent process set prctl(PR_SET_NO_NEW_PRIVS, ...)\n");
+  }
+
+  if (!MoveToNewNamespaces())
+    return 1;
+  if (!SpawnChrootHelper())
+    return 1;
+  if (!DropRoot())
+    return 1;
+  if (!SetupChildEnvironment())
+    return 1;
+
+  execv(argv[1], &argv[1]);
+  FatalError("execv failed");
+
+  return 1;
+}
diff --git a/libchrome/sandbox/linux/syscall_broker/DEPS b/libchrome/sandbox/linux/syscall_broker/DEPS
new file mode 100644
index 0000000..70d9b18
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+sandbox/linux/system_headers",
+]
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_channel.cc b/libchrome/sandbox/linux/syscall_broker/broker_channel.cc
new file mode 100644
index 0000000..fa0f761
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_channel.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 "sandbox/linux/syscall_broker/broker_channel.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// static
+void BrokerChannel::CreatePair(EndPoint* reader, EndPoint* writer) {
+  DCHECK(reader);
+  DCHECK(writer);
+  int socket_pair[2];
+  // Use SOCK_SEQPACKET, to preserve message boundaries but we also want to be
+  // notified (recvmsg should return and not block) when the connection has
+  // been broken which could mean that the other end has been closed.
+  PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socket_pair));
+
+  reader->reset(socket_pair[0]);
+  PCHECK(0 == shutdown(reader->get(), SHUT_WR));
+
+  writer->reset(socket_pair[1]);
+  PCHECK(0 == shutdown(writer->get(), SHUT_RD));
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_channel.h b/libchrome/sandbox/linux/syscall_broker/broker_channel.h
new file mode 100644
index 0000000..2abdba4
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_channel.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// A small class to create a pipe-like communication channel. It is based on a
+// SOCK_SEQPACKET unix socket, which is connection-based and guaranteed to
+// preserve message boundaries.
+class BrokerChannel {
+ public:
+  typedef base::ScopedFD EndPoint;
+  static void CreatePair(EndPoint* reader, EndPoint* writer);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BrokerChannel);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_client.cc b/libchrome/sandbox/linux/syscall_broker/broker_client.cc
new file mode 100644
index 0000000..36c92cd
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_client.cc
@@ -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.
+
+#include "sandbox/linux/syscall_broker/broker_client.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "build/build_config.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+#include "sandbox/linux/syscall_broker/broker_policy.h"
+
+#if defined(OS_ANDROID) && !defined(MSG_CMSG_CLOEXEC)
+#define MSG_CMSG_CLOEXEC 0x40000000
+#endif
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// Make a remote system call over IPC for syscalls that take a path and flags
+// as arguments, currently open() and access().
+// Will return -errno like a real system call.
+// This function needs to be async signal safe.
+int BrokerClient::PathAndFlagsSyscall(IPCCommand syscall_type,
+                                      const char* pathname,
+                                      int flags) const {
+  int recvmsg_flags = 0;
+  RAW_CHECK(syscall_type == COMMAND_OPEN || syscall_type == COMMAND_ACCESS);
+  if (!pathname)
+    return -EFAULT;
+
+  // For this "remote system call" to work, we need to handle any flag that
+  // cannot be sent over a Unix socket in a special way.
+  // See the comments around kCurrentProcessOpenFlagsMask.
+  if (syscall_type == COMMAND_OPEN && (flags & kCurrentProcessOpenFlagsMask)) {
+    // This implementation only knows about O_CLOEXEC, someone needs to look at
+    // this code if other flags are added.
+    RAW_CHECK(kCurrentProcessOpenFlagsMask == O_CLOEXEC);
+    recvmsg_flags |= MSG_CMSG_CLOEXEC;
+    flags &= ~O_CLOEXEC;
+  }
+
+  // There is no point in forwarding a request that we know will be denied.
+  // Of course, the real security check needs to be on the other side of the
+  // IPC.
+  if (fast_check_in_client_) {
+    if (syscall_type == COMMAND_OPEN &&
+        !broker_policy_.GetFileNameIfAllowedToOpen(
+            pathname, flags, NULL /* file_to_open */,
+            NULL /* unlink_after_open */)) {
+      return -broker_policy_.denied_errno();
+    }
+    if (syscall_type == COMMAND_ACCESS &&
+        !broker_policy_.GetFileNameIfAllowedToAccess(pathname, flags, NULL)) {
+      return -broker_policy_.denied_errno();
+    }
+  }
+
+  base::Pickle write_pickle;
+  write_pickle.WriteInt(syscall_type);
+  write_pickle.WriteString(pathname);
+  write_pickle.WriteInt(flags);
+  RAW_CHECK(write_pickle.size() <= kMaxMessageLength);
+
+  int returned_fd = -1;
+  uint8_t reply_buf[kMaxMessageLength];
+
+  // Send a request (in write_pickle) as well that will include a new
+  // temporary socketpair (created internally by SendRecvMsg()).
+  // Then read the reply on this new socketpair in reply_buf and put an
+  // eventual attached file descriptor in |returned_fd|.
+  ssize_t msg_len = base::UnixDomainSocket::SendRecvMsgWithFlags(
+      ipc_channel_.get(), reply_buf, sizeof(reply_buf), recvmsg_flags,
+      &returned_fd, write_pickle);
+  if (msg_len <= 0) {
+    if (!quiet_failures_for_tests_)
+      RAW_LOG(ERROR, "Could not make request to broker process");
+    return -ENOMEM;
+  }
+
+  base::Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
+  base::PickleIterator iter(read_pickle);
+  int return_value = -1;
+  // Now deserialize the return value and eventually return the file
+  // descriptor.
+  if (iter.ReadInt(&return_value)) {
+    switch (syscall_type) {
+      case COMMAND_ACCESS:
+        // We should never have a fd to return.
+        RAW_CHECK(returned_fd == -1);
+        return return_value;
+      case COMMAND_OPEN:
+        if (return_value < 0) {
+          RAW_CHECK(returned_fd == -1);
+          return return_value;
+        } else {
+          // We have a real file descriptor to return.
+          RAW_CHECK(returned_fd >= 0);
+          return returned_fd;
+        }
+      default:
+        RAW_LOG(ERROR, "Unsupported command");
+        return -ENOSYS;
+    }
+  } else {
+    RAW_LOG(ERROR, "Could not read pickle");
+    NOTREACHED();
+    return -ENOMEM;
+  }
+}
+
+BrokerClient::BrokerClient(const BrokerPolicy& broker_policy,
+                           BrokerChannel::EndPoint ipc_channel,
+                           bool fast_check_in_client,
+                           bool quiet_failures_for_tests)
+    : broker_policy_(broker_policy),
+      ipc_channel_(std::move(ipc_channel)),
+      fast_check_in_client_(fast_check_in_client),
+      quiet_failures_for_tests_(quiet_failures_for_tests) {}
+
+BrokerClient::~BrokerClient() {
+}
+
+int BrokerClient::Access(const char* pathname, int mode) const {
+  return PathAndFlagsSyscall(COMMAND_ACCESS, pathname, mode);
+}
+
+int BrokerClient::Open(const char* pathname, int flags) const {
+  return PathAndFlagsSyscall(COMMAND_OPEN, pathname, flags);
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_client.h b/libchrome/sandbox/linux/syscall_broker/broker_client.h
new file mode 100644
index 0000000..2dfef81
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_client.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerPolicy;
+
+// This class can be embedded in a sandboxed process and can be
+// used to perform certain system calls in another, presumably
+// non-sandboxed process (which embeds BrokerHost).
+// A key feature of this class is the ability to use some of its methods in a
+// thread-safe and async-signal safe way. The goal is to be able to use it to
+// replace the open() or access() system calls happening anywhere in a process
+// (as allowed for instance by seccomp-bpf's SIGSYS mechanism).
+class BrokerClient {
+ public:
+  // |policy| needs to match the policy used by BrokerHost. This
+  // allows to predict some of the requests which will be denied
+  // and save an IPC round trip.
+  // |ipc_channel| needs to be a suitable SOCK_SEQPACKET unix socket.
+  // |fast_check_in_client| should be set to true and
+  // |quiet_failures_for_tests| to false unless you are writing tests.
+  BrokerClient(const BrokerPolicy& policy,
+               BrokerChannel::EndPoint ipc_channel,
+               bool fast_check_in_client,
+               bool quiet_failures_for_tests);
+  ~BrokerClient();
+
+  // Can be used in place of access().
+  // X_OK will always return an error in practice since the broker process
+  // doesn't support execute permissions.
+  // It's similar to the access() system call and will return -errno on errors.
+  // This is async signal safe.
+  int Access(const char* pathname, int mode) const;
+  // Can be used in place of open().
+  // The implementation only supports certain white listed flags and will
+  // return -EPERM on other flags.
+  // It's similar to the open() system call and will return -errno on errors.
+  // This is async signal safe.
+  int Open(const char* pathname, int flags) const;
+
+  // Get the file descriptor used for IPC. This is used for tests.
+  int GetIPCDescriptor() const { return ipc_channel_.get(); }
+
+ private:
+  const BrokerPolicy& broker_policy_;
+  const BrokerChannel::EndPoint ipc_channel_;
+  const bool fast_check_in_client_;  // Whether to forward a request that we
+                                     // know will be denied to the broker. (Used
+                                     // for tests).
+  const bool quiet_failures_for_tests_;  // Disable certain error message when
+                                         // testing for failures.
+
+  int PathAndFlagsSyscall(IPCCommand syscall_type,
+                          const char* pathname,
+                          int flags) const;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerClient);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  //  SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_common.h b/libchrome/sandbox/linux/syscall_broker/broker_common.h
new file mode 100644
index 0000000..25aafa7
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_common.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 SANDBOX_LINUX_SYSCALL_BROKER_BROKER_COMMON_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_COMMON_H_
+
+#include <fcntl.h>
+#include <stddef.h>
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+const size_t kMaxMessageLength = 4096;
+
+// Some flags are local to the current process and cannot be sent over a Unix
+// socket. They need special treatment from the client.
+// O_CLOEXEC is tricky because in theory another thread could call execve()
+// before special treatment is made on the client, so a client needs to call
+// recvmsg(2) with MSG_CMSG_CLOEXEC.
+// To make things worse, there are two CLOEXEC related flags, FD_CLOEXEC (see
+// F_GETFD in fcntl(2)) and O_CLOEXEC (see F_GETFL in fcntl(2)). O_CLOEXEC
+// doesn't affect the semantics on execve(), it's merely a note that the
+// descriptor was originally opened with O_CLOEXEC as a flag. And it is sent
+// over unix sockets just fine, so a receiver that would (incorrectly) look at
+// O_CLOEXEC instead of FD_CLOEXEC may be tricked in thinking that the file
+// descriptor will or won't be closed on execve().
+const int kCurrentProcessOpenFlagsMask = O_CLOEXEC;
+
+enum IPCCommand {
+  COMMAND_INVALID = 0,
+  COMMAND_OPEN,
+  COMMAND_ACCESS,
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_COMMON_H_
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_file_permission.cc b/libchrome/sandbox/linux/syscall_broker/broker_file_permission.cc
new file mode 100644
index 0000000..3907344
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_file_permission.cc
@@ -0,0 +1,244 @@
+// 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 "sandbox/linux/syscall_broker/broker_file_permission.h"
+
+#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// Async signal safe
+bool BrokerFilePermission::ValidatePath(const char* path) {
+  if (!path)
+    return false;
+
+  const size_t len = strlen(path);
+  // No empty paths
+  if (len == 0)
+    return false;
+  // Paths must be absolute and not relative
+  if (path[0] != '/')
+    return false;
+  // No trailing / (but "/" is valid)
+  if (len > 1 && path[len - 1] == '/')
+    return false;
+  // No trailing /..
+  if (len >= 3 && path[len - 3] == '/' && path[len - 2] == '.' &&
+      path[len - 1] == '.')
+    return false;
+  // No /../ anywhere
+  for (size_t i = 0; i < len; i++) {
+    if (path[i] == '/' && (len - i) > 3) {
+      if (path[i + 1] == '.' && path[i + 2] == '.' && path[i + 3] == '/') {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+// Async signal safe
+// Calls std::string::c_str(), strncmp and strlen. All these
+// methods are async signal safe in common standard libs.
+// TODO(leecam): remove dependency on std::string
+bool BrokerFilePermission::MatchPath(const char* requested_filename) const {
+  const char* path = path_.c_str();
+  if ((recursive_ && strncmp(requested_filename, path, strlen(path)) == 0)) {
+    // Note: This prefix match will allow any path under the whitelisted
+    // path, for any number of directory levels. E.g. if the whitelisted
+    // path is /good/ then the following will be permitted by the policy.
+    //   /good/file1
+    //   /good/folder/file2
+    //   /good/folder/folder2/file3
+    // If an attacker could make 'folder' a symlink to ../../ they would have
+    // access to the entire filesystem.
+    // Whitelisting with multiple depths is useful, e.g /proc/ but
+    // the system needs to ensure symlinks can not be created!
+    // That said if an attacker can convert any of the absolute paths
+    // to a symlink they can control any file on the system also.
+    return true;
+  } else if (strcmp(requested_filename, path) == 0) {
+    return true;
+  }
+  return false;
+}
+
+// Async signal safe.
+// External call to std::string::c_str() is
+// called in MatchPath.
+// TODO(leecam): remove dependency on std::string
+bool BrokerFilePermission::CheckAccess(const char* requested_filename,
+                                       int mode,
+                                       const char** file_to_access) const {
+  // First, check if |mode| is existence, ability to read or ability
+  // to write. We do not support X_OK.
+  if (mode != F_OK && mode & ~(R_OK | W_OK)) {
+    return false;
+  }
+
+  if (!ValidatePath(requested_filename))
+    return false;
+
+  if (!MatchPath(requested_filename)) {
+    return false;
+  }
+  bool allowed = false;
+  switch (mode) {
+    case F_OK:
+      if (allow_read_ || allow_write_)
+        allowed = true;
+      break;
+    case R_OK:
+      if (allow_read_)
+        allowed = true;
+      break;
+    case W_OK:
+      if (allow_write_)
+        allowed = true;
+      break;
+    case R_OK | W_OK:
+      if (allow_read_ && allow_write_)
+        allowed = true;
+      break;
+    default:
+      return false;
+  }
+
+  if (allowed && file_to_access) {
+    if (!recursive_)
+      *file_to_access = path_.c_str();
+    else
+      *file_to_access = requested_filename;
+  }
+  return allowed;
+}
+
+// Async signal safe.
+// External call to std::string::c_str() is
+// called in MatchPath.
+// TODO(leecam): remove dependency on std::string
+bool BrokerFilePermission::CheckOpen(const char* requested_filename,
+                                     int flags,
+                                     const char** file_to_open,
+                                     bool* unlink_after_open) const {
+  if (!ValidatePath(requested_filename))
+    return false;
+
+  if (!MatchPath(requested_filename)) {
+    return false;
+  }
+
+  // First, check the access mode is valid.
+  const int access_mode = flags & O_ACCMODE;
+  if (access_mode != O_RDONLY && access_mode != O_WRONLY &&
+      access_mode != O_RDWR) {
+    return false;
+  }
+
+  // Check if read is allowed
+  if (!allow_read_ && (access_mode == O_RDONLY || access_mode == O_RDWR)) {
+    return false;
+  }
+
+  // Check if write is allowed
+  if (!allow_write_ && (access_mode == O_WRONLY || access_mode == O_RDWR)) {
+    return false;
+  }
+
+  // Check if file creation is allowed.
+  if (!allow_create_ && (flags & O_CREAT)) {
+    return false;
+  }
+
+  // If O_CREAT is present, ensure O_EXCL
+  if ((flags & O_CREAT) && !(flags & O_EXCL)) {
+    return false;
+  }
+
+  // If this file is to be unlinked, ensure it's created.
+  if (unlink_ && !(flags & O_CREAT)) {
+    return false;
+  }
+
+  // Some flags affect the behavior of the current process. We don't support
+  // them and don't allow them for now.
+  if (flags & kCurrentProcessOpenFlagsMask) {
+    return false;
+  }
+
+  // Now check that all the flags are known to us.
+  const int creation_and_status_flags = flags & ~O_ACCMODE;
+
+  const int known_flags = O_APPEND | O_ASYNC | O_CLOEXEC | O_CREAT | O_DIRECT |
+                          O_DIRECTORY | O_EXCL | O_LARGEFILE | O_NOATIME |
+                          O_NOCTTY | O_NOFOLLOW | O_NONBLOCK | O_NDELAY |
+                          O_SYNC | O_TRUNC;
+
+  const int unknown_flags = ~known_flags;
+  const bool has_unknown_flags = creation_and_status_flags & unknown_flags;
+
+  if (has_unknown_flags)
+    return false;
+
+  if (file_to_open) {
+    if (!recursive_)
+      *file_to_open = path_.c_str();
+    else
+      *file_to_open = requested_filename;
+  }
+  if (unlink_after_open)
+    *unlink_after_open = unlink_;
+
+  return true;
+}
+
+const char* BrokerFilePermission::GetErrorMessageForTests() {
+  static char kInvalidBrokerFileString[] = "Invalid BrokerFilePermission";
+  return kInvalidBrokerFileString;
+}
+
+BrokerFilePermission::BrokerFilePermission(const std::string& path,
+                                           bool recursive,
+                                           bool unlink,
+                                           bool allow_read,
+                                           bool allow_write,
+                                           bool allow_create)
+    : path_(path),
+      recursive_(recursive),
+      unlink_(unlink),
+      allow_read_(allow_read),
+      allow_write_(allow_write),
+      allow_create_(allow_create) {
+  // Validate this permission and die if invalid!
+
+  // Must have enough length for a '/'
+  CHECK(path_.length() > 0) << GetErrorMessageForTests();
+  // Whitelisted paths must be absolute.
+  CHECK(path_[0] == '/') << GetErrorMessageForTests();
+
+  // Don't allow unlinking on creation without create permission
+  if (unlink_) {
+    CHECK(allow_create) << GetErrorMessageForTests();
+  }
+  const char last_char = *(path_.rbegin());
+  // Recursive paths must have a trailing slash
+  if (recursive_) {
+    CHECK(last_char == '/') << GetErrorMessageForTests();
+  } else {
+    CHECK(last_char != '/') << GetErrorMessageForTests();
+  }
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
\ No newline at end of file
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_file_permission.h b/libchrome/sandbox/linux/syscall_broker/broker_file_permission.h
new file mode 100644
index 0000000..03300d1
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_file_permission.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 SANDBOX_LINUX_SYSCALL_BROKER_BROKER_FILE_PERMISSION_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_FILE_PERMISSION_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// BrokerFilePermission defines a path for whitelisting.
+// Pick the correct static factory method to create a permission.
+// CheckOpen and CheckAccess are async signal safe.
+// Constuction and Destruction are not async signal safe.
+// |path| is the path to be whitelisted.
+class SANDBOX_EXPORT BrokerFilePermission {
+ public:
+  ~BrokerFilePermission() {}
+  BrokerFilePermission(const BrokerFilePermission&) = default;
+  BrokerFilePermission& operator=(const BrokerFilePermission&) = default;
+
+  static BrokerFilePermission ReadOnly(const std::string& path) {
+    return BrokerFilePermission(path, false, false, true, false, false);
+  }
+
+  static BrokerFilePermission ReadOnlyRecursive(const std::string& path) {
+    return BrokerFilePermission(path, true, false, true, false, false);
+  }
+
+  static BrokerFilePermission WriteOnly(const std::string& path) {
+    return BrokerFilePermission(path, false, false, false, true, false);
+  }
+
+  static BrokerFilePermission ReadWrite(const std::string& path) {
+    return BrokerFilePermission(path, false, false, true, true, false);
+  }
+
+  static BrokerFilePermission ReadWriteCreate(const std::string& path) {
+    return BrokerFilePermission(path, false, false, true, true, true);
+  }
+
+  static BrokerFilePermission ReadWriteCreateUnlink(const std::string& path) {
+    return BrokerFilePermission(path, false, true, true, true, true);
+  }
+
+  static BrokerFilePermission ReadWriteCreateUnlinkRecursive(
+      const std::string& path) {
+    return BrokerFilePermission(path, true, true, true, true, true);
+  }
+
+  // Returns true if |requested_filename| is allowed to be opened
+  // by this permission.
+  // If |file_to_open| is not NULL it is set to point to either
+  // the |requested_filename| in the case of a recursive match,
+  // or a pointer the matched path in the whitelist if an absolute
+  // match.
+  // If not NULL |unlink_after_open| is set to point to true if the
+  // caller should unlink the path after openning.
+  // Async signal safe if |file_to_open| is NULL.
+  bool CheckOpen(const char* requested_filename,
+                 int flags,
+                 const char** file_to_open,
+                 bool* unlink_after_open) const;
+  // Returns true if |requested_filename| is allowed to be accessed
+  // by this permission as per access(2).
+  // If |file_to_open| is not NULL it is set to point to either
+  // the |requested_filename| in the case of a recursive match,
+  // or a pointer to the matched path in the whitelist if an absolute
+  // match.
+  // |mode| is per mode argument of access(2).
+  // Async signal safe if |file_to_access| is NULL
+  bool CheckAccess(const char* requested_filename,
+                   int mode,
+                   const char** file_to_access) const;
+
+ private:
+  friend class BrokerFilePermissionTester;
+  BrokerFilePermission(const std::string& path,
+                       bool recursive,
+                       bool unlink,
+                       bool allow_read,
+                       bool allow_write,
+                       bool allow_create);
+
+  // ValidatePath checks |path| and returns true if these conditions are met
+  // * Greater than 0 length
+  // * Is an absolute path
+  // * No trailing slash
+  // * No /../ path traversal
+  static bool ValidatePath(const char* path);
+
+  // MatchPath returns true if |requested_filename| is covered by this instance
+  bool MatchPath(const char* requested_filename) const;
+
+  // Used in by BrokerFilePermissionTester for tests.
+  static const char* GetErrorMessageForTests();
+
+  // These are not const as std::vector requires copy-assignment and this class
+  // is stored in vectors. All methods are marked const so
+  // the compiler will still enforce no changes outside of the constructor.
+  std::string path_;
+  bool recursive_;  // Allow everything under this path. |path| must be a dir.
+  bool unlink_;     // unlink after opening.
+  bool allow_read_;
+  bool allow_write_;
+  bool allow_create_;
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  //  SANDBOX_LINUX_SYSCALL_BROKER_BROKER_FILE_PERMISSION_H_
\ No newline at end of file
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc b/libchrome/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
new file mode 100644
index 0000000..b58a901
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
@@ -0,0 +1,262 @@
+// 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 "sandbox/linux/syscall_broker/broker_file_permission.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerFilePermissionTester {
+ public:
+  static bool ValidatePath(const char* path) {
+    return BrokerFilePermission::ValidatePath(path);
+  }
+  static const char* GetErrorMessage() {
+    return BrokerFilePermission::GetErrorMessageForTests();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BrokerFilePermissionTester);
+};
+
+namespace {
+
+// Creation tests are DEATH tests as a bad permission causes termination.
+SANDBOX_TEST(BrokerFilePermission, CreateGood) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+SANDBOX_TEST(BrokerFilePermission, CreateGoodRecursive) {
+  const char kPath[] = "/tmp/good/";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBad,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "/tmp/bad/";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBadRecursive,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "/tmp/bad";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBadNotAbs,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "tmp/bad";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+SANDBOX_DEATH_TEST(
+    BrokerFilePermission,
+    CreateBadEmpty,
+    DEATH_MESSAGE(BrokerFilePermissionTester::GetErrorMessage())) {
+  const char kPath[] = "";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+}
+
+// CheckPerm tests |path| against |perm| given |access_flags|.
+// If |create| is true then file creation is tested for success.
+void CheckPerm(const BrokerFilePermission& perm,
+               const char* path,
+               int access_flags,
+               bool create) {
+  const char* file_to_open = NULL;
+
+  ASSERT_FALSE(perm.CheckAccess(path, X_OK, NULL));
+  ASSERT_TRUE(perm.CheckAccess(path, F_OK, NULL));
+  // check bad perms
+  switch (access_flags) {
+    case O_RDONLY:
+      ASSERT_TRUE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, R_OK, NULL));
+      ASSERT_FALSE(perm.CheckAccess(path, W_OK, NULL));
+      break;
+    case O_WRONLY:
+      ASSERT_FALSE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
+      ASSERT_FALSE(perm.CheckAccess(path, R_OK, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, W_OK, NULL));
+      break;
+    case O_RDWR:
+      ASSERT_TRUE(perm.CheckOpen(path, O_RDONLY, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckOpen(path, O_WRONLY, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckOpen(path, O_RDWR, &file_to_open, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, R_OK, NULL));
+      ASSERT_TRUE(perm.CheckAccess(path, W_OK, NULL));
+      break;
+    default:
+      // Bad test case
+      NOTREACHED();
+  }
+
+// O_SYNC can be defined as (__O_SYNC|O_DSYNC)
+#ifdef O_DSYNC
+  const int kSyncFlag = O_SYNC & ~O_DSYNC;
+#else
+  const int kSyncFlag = O_SYNC;
+#endif
+
+  const int kNumberOfBitsInOAccMode = 2;
+  static_assert(O_ACCMODE == ((1 << kNumberOfBitsInOAccMode) - 1),
+                "incorrect number of bits");
+  // check every possible flag and act accordingly.
+  // Skipping AccMode bits as they are present in every case.
+  for (int i = kNumberOfBitsInOAccMode; i < 32; i++) {
+    int flag = 1 << i;
+    switch (flag) {
+      case O_APPEND:
+      case O_ASYNC:
+      case O_DIRECT:
+      case O_DIRECTORY:
+#ifdef O_DSYNC
+      case O_DSYNC:
+#endif
+      case O_EXCL:
+      case O_LARGEFILE:
+      case O_NOATIME:
+      case O_NOCTTY:
+      case O_NOFOLLOW:
+      case O_NONBLOCK:
+#if (O_NONBLOCK != O_NDELAY)
+      case O_NDELAY:
+#endif
+      case kSyncFlag:
+      case O_TRUNC:
+        ASSERT_TRUE(
+            perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
+        break;
+      case O_CLOEXEC:
+      case O_CREAT:
+      default:
+        ASSERT_FALSE(
+            perm.CheckOpen(path, access_flags | flag, &file_to_open, NULL));
+    }
+  }
+  if (create) {
+    bool unlink;
+    ASSERT_TRUE(perm.CheckOpen(path, O_CREAT | O_EXCL | access_flags,
+                               &file_to_open, &unlink));
+    ASSERT_FALSE(unlink);
+  } else {
+    ASSERT_FALSE(perm.CheckOpen(path, O_CREAT | O_EXCL | access_flags,
+                                &file_to_open, NULL));
+  }
+}
+
+TEST(BrokerFilePermission, ReadOnly) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath);
+  CheckPerm(perm, kPath, O_RDONLY, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadOnlyRecursive) {
+  const char kPath[] = "/tmp/good/";
+  const char kPathFile[] = "/tmp/good/file";
+  BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath);
+  CheckPerm(perm, kPathFile, O_RDONLY, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, WriteOnly) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::WriteOnly(kPath);
+  CheckPerm(perm, kPath, O_WRONLY, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadWrite) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadWrite(kPath);
+  CheckPerm(perm, kPath, O_RDWR, false);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadWriteCreate) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm = BrokerFilePermission::ReadWriteCreate(kPath);
+  CheckPerm(perm, kPath, O_RDWR, true);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+void CheckUnlink(BrokerFilePermission& perm,
+                 const char* path,
+                 int access_flags) {
+  bool unlink;
+  ASSERT_FALSE(perm.CheckOpen(path, access_flags, NULL, &unlink));
+  ASSERT_FALSE(perm.CheckOpen(path, access_flags | O_CREAT, NULL, &unlink));
+  ASSERT_TRUE(
+      perm.CheckOpen(path, access_flags | O_CREAT | O_EXCL, NULL, &unlink));
+  ASSERT_TRUE(unlink);
+}
+
+TEST(BrokerFilePermission, ReadWriteCreateUnlink) {
+  const char kPath[] = "/tmp/good";
+  BrokerFilePermission perm =
+      BrokerFilePermission::ReadWriteCreateUnlink(kPath);
+  CheckUnlink(perm, kPath, O_RDWR);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ReadWriteCreateUnlinkRecursive) {
+  const char kPath[] = "/tmp/good/";
+  const char kPathFile[] = "/tmp/good/file";
+  BrokerFilePermission perm =
+      BrokerFilePermission::ReadWriteCreateUnlinkRecursive(kPath);
+  CheckUnlink(perm, kPathFile, O_RDWR);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerFilePermission, ValidatePath) {
+  EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/path"));
+  EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/"));
+  EXPECT_TRUE(BrokerFilePermissionTester::ValidatePath("/..path"));
+
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath(""));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("bad"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("bad/"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/.."));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/bad/../bad"));
+  EXPECT_FALSE(BrokerFilePermissionTester::ValidatePath("/../bad"));
+}
+
+}  // namespace
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_host.cc b/libchrome/sandbox/linux/syscall_broker/broker_host.cc
new file mode 100644
index 0000000..dd61dac
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_host.cc
@@ -0,0 +1,232 @@
+// 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 "sandbox/linux/syscall_broker/broker_host.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+#include "sandbox/linux/syscall_broker/broker_policy.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+namespace {
+
+bool IsRunningOnValgrind() {
+  return RUNNING_ON_VALGRIND;
+}
+
+// A little open(2) wrapper to handle some oddities for us. In the general case
+// make a direct system call since we want to keep in control of the broker
+// process' system calls profile to be able to loosely sandbox it.
+int sys_open(const char* pathname, int flags) {
+  // Hardcode mode to rw------- when creating files.
+  int mode;
+  if (flags & O_CREAT) {
+    mode = 0600;
+  } else {
+    mode = 0;
+  }
+  if (IsRunningOnValgrind()) {
+    // Valgrind does not support AT_FDCWD, just use libc's open() in this case.
+    return open(pathname, flags, mode);
+  } else {
+    return syscall(__NR_openat, AT_FDCWD, pathname, flags, mode);
+  }
+}
+
+// Open |requested_filename| with |flags| if allowed by our policy.
+// Write the syscall return value (-errno) to |write_pickle| and append
+// a file descriptor to |opened_files| if relevant.
+void OpenFileForIPC(const BrokerPolicy& policy,
+                    const std::string& requested_filename,
+                    int flags,
+                    base::Pickle* write_pickle,
+                    std::vector<int>* opened_files) {
+  DCHECK(write_pickle);
+  DCHECK(opened_files);
+  const char* file_to_open = NULL;
+  bool unlink_after_open = false;
+  const bool safe_to_open_file = policy.GetFileNameIfAllowedToOpen(
+      requested_filename.c_str(), flags, &file_to_open, &unlink_after_open);
+
+  if (safe_to_open_file) {
+    CHECK(file_to_open);
+    int opened_fd = sys_open(file_to_open, flags);
+    if (opened_fd < 0) {
+      write_pickle->WriteInt(-errno);
+    } else {
+      // Success.
+      if (unlink_after_open) {
+        unlink(file_to_open);
+      }
+      opened_files->push_back(opened_fd);
+      write_pickle->WriteInt(0);
+    }
+  } else {
+    write_pickle->WriteInt(-policy.denied_errno());
+  }
+}
+
+// Perform access(2) on |requested_filename| with mode |mode| if allowed by our
+// policy. Write the syscall return value (-errno) to |write_pickle|.
+void AccessFileForIPC(const BrokerPolicy& policy,
+                      const std::string& requested_filename,
+                      int mode,
+                      base::Pickle* write_pickle) {
+  DCHECK(write_pickle);
+  const char* file_to_access = NULL;
+  const bool safe_to_access_file = policy.GetFileNameIfAllowedToAccess(
+      requested_filename.c_str(), mode, &file_to_access);
+
+  if (safe_to_access_file) {
+    CHECK(file_to_access);
+    int access_ret = access(file_to_access, mode);
+    int access_errno = errno;
+    if (!access_ret)
+      write_pickle->WriteInt(0);
+    else
+      write_pickle->WriteInt(-access_errno);
+  } else {
+    write_pickle->WriteInt(-policy.denied_errno());
+  }
+}
+
+// Handle a |command_type| request contained in |iter| and send the reply
+// on |reply_ipc|.
+// Currently COMMAND_OPEN and COMMAND_ACCESS are supported.
+bool HandleRemoteCommand(const BrokerPolicy& policy,
+                         IPCCommand command_type,
+                         int reply_ipc,
+                         base::PickleIterator iter) {
+  // Currently all commands have two arguments: filename and flags.
+  std::string requested_filename;
+  int flags = 0;
+  if (!iter.ReadString(&requested_filename) || !iter.ReadInt(&flags))
+    return false;
+
+  base::Pickle write_pickle;
+  std::vector<int> opened_files;
+
+  switch (command_type) {
+    case COMMAND_ACCESS:
+      AccessFileForIPC(policy, requested_filename, flags, &write_pickle);
+      break;
+    case COMMAND_OPEN:
+      OpenFileForIPC(
+          policy, requested_filename, flags, &write_pickle, &opened_files);
+      break;
+    default:
+      LOG(ERROR) << "Invalid IPC command";
+      break;
+  }
+
+  CHECK_LE(write_pickle.size(), kMaxMessageLength);
+  ssize_t sent = base::UnixDomainSocket::SendMsg(
+      reply_ipc, write_pickle.data(), write_pickle.size(), opened_files);
+
+  // Close anything we have opened in this process.
+  for (std::vector<int>::iterator it = opened_files.begin();
+       it != opened_files.end();
+       ++it) {
+    int ret = IGNORE_EINTR(close(*it));
+    DCHECK(!ret) << "Could not close file descriptor";
+  }
+
+  if (sent <= 0) {
+    LOG(ERROR) << "Could not send IPC reply";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+BrokerHost::BrokerHost(const BrokerPolicy& broker_policy,
+                       BrokerChannel::EndPoint ipc_channel)
+    : broker_policy_(broker_policy), ipc_channel_(std::move(ipc_channel)) {}
+
+BrokerHost::~BrokerHost() {
+}
+
+// Handle a request on the IPC channel ipc_channel_.
+// A request should have a file descriptor attached on which we will reply and
+// that we will then close.
+// A request should start with an int that will be used as the command type.
+BrokerHost::RequestStatus BrokerHost::HandleRequest() const {
+  std::vector<base::ScopedFD> fds;
+  char buf[kMaxMessageLength];
+  errno = 0;
+  const ssize_t msg_len = base::UnixDomainSocket::RecvMsg(
+      ipc_channel_.get(), buf, sizeof(buf), &fds);
+
+  if (msg_len == 0 || (msg_len == -1 && errno == ECONNRESET)) {
+    // EOF from the client, or the client died, we should die.
+    return RequestStatus::LOST_CLIENT;
+  }
+
+  // The client should send exactly one file descriptor, on which we
+  // will write the reply.
+  if (msg_len < 0 || fds.size() != 1 || fds[0].get() < 0) {
+    PLOG(ERROR) << "Error reading message from the client";
+    return RequestStatus::FAILURE;
+  }
+
+  base::ScopedFD temporary_ipc(std::move(fds[0]));
+
+  base::Pickle pickle(buf, msg_len);
+  base::PickleIterator iter(pickle);
+  int command_type;
+  if (iter.ReadInt(&command_type)) {
+    bool command_handled = false;
+    // Go through all the possible IPC messages.
+    switch (command_type) {
+      case COMMAND_ACCESS:
+      case COMMAND_OPEN:
+        // We reply on the file descriptor sent to us via the IPC channel.
+        command_handled = HandleRemoteCommand(
+            broker_policy_, static_cast<IPCCommand>(command_type),
+            temporary_ipc.get(), iter);
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+
+    if (command_handled) {
+      return RequestStatus::SUCCESS;
+    } else {
+      return RequestStatus::FAILURE;
+    }
+
+    NOTREACHED();
+  }
+
+  LOG(ERROR) << "Error parsing IPC request";
+  return RequestStatus::FAILURE;
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_host.h b/libchrome/sandbox/linux/syscall_broker/broker_host.h
new file mode 100644
index 0000000..9866507
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_host.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 SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerPolicy;
+
+// The BrokerHost class should be embedded in a (presumably not sandboxed)
+// process. It will honor IPC requests from a BrokerClient sent over
+// |ipc_channel| according to |broker_policy|.
+class BrokerHost {
+ public:
+  enum class RequestStatus { LOST_CLIENT = 0, SUCCESS, FAILURE };
+
+  BrokerHost(const BrokerPolicy& broker_policy,
+             BrokerChannel::EndPoint ipc_channel);
+  ~BrokerHost();
+
+  RequestStatus HandleRequest() const;
+
+ private:
+  const BrokerPolicy& broker_policy_;
+  const BrokerChannel::EndPoint ipc_channel_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerHost);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  //  SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_policy.cc b/libchrome/sandbox/linux/syscall_broker/broker_policy.cc
new file mode 100644
index 0000000..cd09245
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_policy.cc
@@ -0,0 +1,100 @@
+// 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 "sandbox/linux/syscall_broker/broker_policy.h"
+
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "sandbox/linux/syscall_broker/broker_common.h"
+
+namespace sandbox {
+namespace syscall_broker {
+
+BrokerPolicy::BrokerPolicy(int denied_errno,
+                           const std::vector<BrokerFilePermission>& permissions)
+    : denied_errno_(denied_errno),
+      permissions_(permissions),
+      num_of_permissions_(permissions.size()) {
+  // The spec guarantees vectors store their elements contiguously
+  // so set up a pointer to array of element so it can be used
+  // in async signal safe code instead of vector operations.
+  if (num_of_permissions_ > 0) {
+    permissions_array_ = &permissions_[0];
+  } else {
+    permissions_array_ = NULL;
+  }
+}
+
+BrokerPolicy::~BrokerPolicy() {
+}
+
+// Check if calling access() should be allowed on |requested_filename| with
+// mode |requested_mode|.
+// Note: access() being a system call to check permissions, this can get a bit
+// confusing. We're checking if calling access() should even be allowed with
+// the same policy we would use for open().
+// If |file_to_access| is not NULL, we will return the matching pointer from
+// the whitelist. For paranoia a caller should then use |file_to_access|. See
+// GetFileNameIfAllowedToOpen() for more explanation.
+// return true if calling access() on this file should be allowed, false
+// otherwise.
+// Async signal safe if and only if |file_to_access| is NULL.
+bool BrokerPolicy::GetFileNameIfAllowedToAccess(
+    const char* requested_filename,
+    int requested_mode,
+    const char** file_to_access) const {
+  if (file_to_access && *file_to_access) {
+    // Make sure that callers never pass a non-empty string. In case callers
+    // wrongly forget to check the return value and look at the string
+    // instead, this could catch bugs.
+    RAW_LOG(FATAL, "*file_to_access should be NULL");
+    return false;
+  }
+  for (size_t i = 0; i < num_of_permissions_; i++) {
+    if (permissions_array_[i].CheckAccess(requested_filename, requested_mode,
+                                          file_to_access)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Check if |requested_filename| can be opened with flags |requested_flags|.
+// If |file_to_open| is not NULL, we will return the matching pointer from the
+// whitelist. For paranoia, a caller should then use |file_to_open| rather
+// than |requested_filename|, so that it never attempts to open an
+// attacker-controlled file name, even if an attacker managed to fool the
+// string comparison mechanism.
+// Return true if opening should be allowed, false otherwise.
+// Async signal safe if and only if |file_to_open| is NULL.
+bool BrokerPolicy::GetFileNameIfAllowedToOpen(const char* requested_filename,
+                                              int requested_flags,
+                                              const char** file_to_open,
+                                              bool* unlink_after_open) const {
+  if (file_to_open && *file_to_open) {
+    // Make sure that callers never pass a non-empty string. In case callers
+    // wrongly forget to check the return value and look at the string
+    // instead, this could catch bugs.
+    RAW_LOG(FATAL, "*file_to_open should be NULL");
+    return false;
+  }
+  for (size_t i = 0; i < num_of_permissions_; i++) {
+    if (permissions_array_[i].CheckOpen(requested_filename, requested_flags,
+                                        file_to_open, unlink_after_open)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_policy.h b/libchrome/sandbox/linux/syscall_broker/broker_policy.h
new file mode 100644
index 0000000..58bc29a
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_policy.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 SANDBOX_LINUX_SYSCALL_BROKER_BROKER_POLICY_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_POLICY_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+#include "sandbox/linux/syscall_broker/broker_file_permission.h"
+
+namespace sandbox {
+namespace syscall_broker {
+
+// BrokerPolicy allows to define the security policy enforced by a
+// BrokerHost. The BrokerHost will evaluate requests sent over its
+// IPC channel according to the BrokerPolicy.
+// Some of the methods of this class can be used in an async-signal safe
+// way.
+class BrokerPolicy {
+ public:
+  // |denied_errno| is the error code returned when IPC requests for system
+  // calls such as open() or access() are denied because a file is not in the
+  // whitelist. EACCESS would be a typical value.
+  // |permissions| is a list of BrokerPermission objects that define
+  // what the broker will allow.
+  BrokerPolicy(int denied_errno,
+               const std::vector<BrokerFilePermission>& permissions);
+
+  ~BrokerPolicy();
+
+  // Check if calling access() should be allowed on |requested_filename| with
+  // mode |requested_mode|.
+  // Note: access() being a system call to check permissions, this can get a bit
+  // confusing. We're checking if calling access() should even be allowed with
+  // If |file_to_open| is not NULL, a pointer to the path will be returned.
+  // In the case of a recursive match, this will be the requested_filename,
+  // otherwise it will return the matching pointer from the
+  // whitelist. For paranoia a caller should then use |file_to_access|. See
+  // GetFileNameIfAllowedToOpen() for more explanation.
+  // return true if calling access() on this file should be allowed, false
+  // otherwise.
+  // Async signal safe if and only if |file_to_access| is NULL.
+  bool GetFileNameIfAllowedToAccess(const char* requested_filename,
+                                    int requested_mode,
+                                    const char** file_to_access) const;
+
+  // Check if |requested_filename| can be opened with flags |requested_flags|.
+  // If |file_to_open| is not NULL, a pointer to the path will be returned.
+  // In the case of a recursive match, this will be the requested_filename,
+  // otherwise it will return the matching pointer from the
+  // whitelist. For paranoia, a caller should then use |file_to_open| rather
+  // than |requested_filename|, so that it never attempts to open an
+  // attacker-controlled file name, even if an attacker managed to fool the
+  // string comparison mechanism.
+  // |unlink_after_open| if not NULL will be set to point to true if the
+  // policy requests the caller unlink the path after opening.
+  // Return true if opening should be allowed, false otherwise.
+  // Async signal safe if and only if |file_to_open| is NULL.
+  bool GetFileNameIfAllowedToOpen(const char* requested_filename,
+                                  int requested_flags,
+                                  const char** file_to_open,
+                                  bool* unlink_after_open) const;
+  int denied_errno() const { return denied_errno_; }
+
+ private:
+  const int denied_errno_;
+  // The permissions_ vector is used as storage for the BrokerFilePermission
+  // objects but is not referenced outside of the constructor as
+  // vectors are unfriendly in async signal safe code.
+  const std::vector<BrokerFilePermission> permissions_;
+  // permissions_array_ is set up to point to the backing store of
+  // permissions_ and is used in async signal safe methods.
+  const BrokerFilePermission* permissions_array_;
+  const size_t num_of_permissions_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerPolicy);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_POLICY_H_
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_process.cc b/libchrome/sandbox/linux/syscall_broker/broker_process.cc
new file mode 100644
index 0000000..30713ce
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_process.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 "sandbox/linux/syscall_broker/broker_process.h"
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "build/build_config.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
+#include "sandbox/linux/syscall_broker/broker_client.h"
+#include "sandbox/linux/syscall_broker/broker_host.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+BrokerProcess::BrokerProcess(
+    int denied_errno,
+    const std::vector<syscall_broker::BrokerFilePermission>& permissions,
+    bool fast_check_in_client,
+    bool quiet_failures_for_tests)
+    : initialized_(false),
+      fast_check_in_client_(fast_check_in_client),
+      quiet_failures_for_tests_(quiet_failures_for_tests),
+      broker_pid_(-1),
+      policy_(denied_errno, permissions) {
+}
+
+BrokerProcess::~BrokerProcess() {
+  if (initialized_) {
+    if (broker_client_.get()) {
+      // Closing the socket should be enough to notify the child to die,
+      // unless it has been duplicated.
+      CloseChannel();
+    }
+    PCHECK(0 == kill(broker_pid_, SIGKILL));
+    siginfo_t process_info;
+    // Reap the child.
+    int ret = HANDLE_EINTR(waitid(P_PID, broker_pid_, &process_info, WEXITED));
+    PCHECK(0 == ret);
+  }
+}
+
+bool BrokerProcess::Init(
+    const base::Callback<bool(void)>& broker_process_init_callback) {
+  CHECK(!initialized_);
+  BrokerChannel::EndPoint ipc_reader;
+  BrokerChannel::EndPoint ipc_writer;
+  BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
+
+#if !defined(THREAD_SANITIZER)
+  DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
+#endif
+  int child_pid = fork();
+  if (child_pid == -1) {
+    return false;
+  }
+  if (child_pid) {
+    // We are the parent and we have just forked our broker process.
+    ipc_reader.reset();
+    broker_pid_ = child_pid;
+    broker_client_.reset(new BrokerClient(policy_, std::move(ipc_writer),
+                                          fast_check_in_client_,
+                                          quiet_failures_for_tests_));
+    initialized_ = true;
+    return true;
+  } else {
+    // We are the broker process. Make sure to close the writer's end so that
+    // we get notified if the client disappears.
+    ipc_writer.reset();
+    CHECK(broker_process_init_callback.Run());
+    BrokerHost broker_host(policy_, std::move(ipc_reader));
+    for (;;) {
+      switch (broker_host.HandleRequest()) {
+        case BrokerHost::RequestStatus::LOST_CLIENT:
+          _exit(1);
+        case BrokerHost::RequestStatus::SUCCESS:
+        case BrokerHost::RequestStatus::FAILURE:
+          continue;
+      }
+    }
+    _exit(1);
+  }
+  NOTREACHED();
+  return false;
+}
+
+void BrokerProcess::CloseChannel() {
+  broker_client_.reset();
+}
+
+int BrokerProcess::Access(const char* pathname, int mode) const {
+  RAW_CHECK(initialized_);
+  return broker_client_->Access(pathname, mode);
+}
+
+int BrokerProcess::Open(const char* pathname, int flags) const {
+  RAW_CHECK(initialized_);
+  return broker_client_->Open(pathname, flags);
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox.
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_process.h b/libchrome/sandbox/linux/syscall_broker/broker_process.h
new file mode 100644
index 0000000..3c0c809
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_process.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
+#define SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/pickle.h"
+#include "base/process/process.h"
+#include "sandbox/linux/syscall_broker/broker_policy.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerClient;
+class BrokerFilePermission;
+
+// Create a new "broker" process to which we can send requests via an IPC
+// channel by forking the current process.
+// This is a low level IPC mechanism that is suitable to be called from a
+// signal handler.
+// A process would typically create a broker process before entering
+// sandboxing.
+// 1. BrokerProcess open_broker(read_whitelist, write_whitelist);
+// 2. CHECK(open_broker.Init(NULL));
+// 3. Enable sandbox.
+// 4. Use open_broker.Open() to open files.
+class SANDBOX_EXPORT BrokerProcess {
+ public:
+  // |denied_errno| is the error code returned when methods such as Open()
+  // or Access() are invoked on a file which is not in the whitelist. EACCESS
+  // would be a typical value.
+  // |allowed_r_files| and |allowed_w_files| are white lists of files that can
+  // be opened later via the Open() API, respectively for reading and writing.
+  // A file available read-write should be listed in both.
+  // |fast_check_in_client| and |quiet_failures_for_tests| are reserved for
+  // unit tests, don't use it.
+
+  BrokerProcess(
+      int denied_errno,
+      const std::vector<syscall_broker::BrokerFilePermission>& permissions,
+      bool fast_check_in_client = true,
+      bool quiet_failures_for_tests = false);
+
+  ~BrokerProcess();
+  // Will initialize the broker process. There should be no threads at this
+  // point, since we need to fork().
+  // broker_process_init_callback will be called in the new broker process,
+  // after fork() returns.
+  bool Init(const base::Callback<bool(void)>& broker_process_init_callback);
+
+  // Can be used in place of access(). Will be async signal safe.
+  // X_OK will always return an error in practice since the broker process
+  // doesn't support execute permissions.
+  // It's similar to the access() system call and will return -errno on errors.
+  int Access(const char* pathname, int mode) const;
+  // Can be used in place of open(). Will be async signal safe.
+  // The implementation only supports certain white listed flags and will
+  // return -EPERM on other flags.
+  // It's similar to the open() system call and will return -errno on errors.
+  int Open(const char* pathname, int flags) const;
+
+  int broker_pid() const { return broker_pid_; }
+
+ private:
+  friend class BrokerProcessTestHelper;
+
+  // Close the IPC channel with the other party. This should only be used
+  // by tests an none of the class methods should be used afterwards.
+  void CloseChannel();
+
+  bool initialized_;  // Whether we've been through Init() yet.
+  const bool fast_check_in_client_;
+  const bool quiet_failures_for_tests_;
+  pid_t broker_pid_;                     // The PID of the broker (child).
+  syscall_broker::BrokerPolicy policy_;  // The sandboxing policy.
+  std::unique_ptr<syscall_broker::BrokerClient> broker_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrokerProcess);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
diff --git a/libchrome/sandbox/linux/syscall_broker/broker_process_unittest.cc b/libchrome/sandbox/linux/syscall_broker/broker_process_unittest.cc
new file mode 100644
index 0000000..229764a
--- /dev/null
+++ b/libchrome/sandbox/linux/syscall_broker/broker_process_unittest.cc
@@ -0,0 +1,666 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/syscall_broker/broker_process.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stddef.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "sandbox/linux/syscall_broker/broker_client.h"
+#include "sandbox/linux/tests/scoped_temporary_file.h"
+#include "sandbox/linux/tests/test_utils.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+class BrokerProcessTestHelper {
+ public:
+  static void CloseChannel(BrokerProcess* broker) { broker->CloseChannel(); }
+  // Get the client's IPC descriptor to send IPC requests directly.
+  // TODO(jln): refator tests to get rid of this.
+  static int GetIPCDescriptor(const BrokerProcess* broker) {
+    return broker->broker_client_->GetIPCDescriptor();
+  }
+};
+
+namespace {
+
+bool NoOpCallback() {
+  return true;
+}
+
+}  // namespace
+
+TEST(BrokerProcess, CreateAndDestroy) {
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
+
+  std::unique_ptr<BrokerProcess> open_broker(
+      new BrokerProcess(EPERM, permissions));
+  ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
+
+  ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
+  // Destroy the broker and check it has exited properly.
+  open_broker.reset();
+  ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
+}
+
+TEST(BrokerProcess, TestOpenAccessNull) {
+  std::vector<BrokerFilePermission> empty;
+  BrokerProcess open_broker(EPERM, empty);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  int fd = open_broker.Open(NULL, O_RDONLY);
+  ASSERT_EQ(fd, -EFAULT);
+
+  int ret = open_broker.Access(NULL, F_OK);
+  ASSERT_EQ(ret, -EFAULT);
+}
+
+void TestOpenFilePerms(bool fast_check_in_client, int denied_errno) {
+  const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1";
+  // We can't debug the init process, and shouldn't be able to access
+  // its auxv file.
+  const char kR_WhiteListedButDenied[] = "/proc/1/auxv";
+  const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2";
+  const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3";
+  const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4";
+
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kR_WhiteListed));
+  permissions.push_back(
+      BrokerFilePermission::ReadOnly(kR_WhiteListedButDenied));
+  permissions.push_back(BrokerFilePermission::WriteOnly(kW_WhiteListed));
+  permissions.push_back(BrokerFilePermission::ReadWrite(kRW_WhiteListed));
+
+  BrokerProcess open_broker(denied_errno, permissions, fast_check_in_client);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  int fd = -1;
+  fd = open_broker.Open(kR_WhiteListed, O_RDONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kR_WhiteListed, O_WRONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(kR_WhiteListed, O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+  int ret = -1;
+  ret = open_broker.Access(kR_WhiteListed, F_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kR_WhiteListed, R_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kR_WhiteListed, W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kR_WhiteListed, R_OK | W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kR_WhiteListed, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kR_WhiteListed, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  // Android sometimes runs tests as root.
+  // This part of the test requires a process that doesn't have
+  // CAP_DAC_OVERRIDE. We check against a root euid as a proxy for that.
+  if (geteuid()) {
+    fd = open_broker.Open(kR_WhiteListedButDenied, O_RDONLY);
+    // The broker process will allow this, but the normal permission system
+    // won't.
+    ASSERT_EQ(fd, -EACCES);
+    fd = open_broker.Open(kR_WhiteListedButDenied, O_WRONLY);
+    ASSERT_EQ(fd, -denied_errno);
+    fd = open_broker.Open(kR_WhiteListedButDenied, O_RDWR);
+    ASSERT_EQ(fd, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, F_OK);
+    // The normal permission system will let us check that the file exists.
+    ASSERT_EQ(ret, 0);
+    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK);
+    ASSERT_EQ(ret, -EACCES);
+    ret = open_broker.Access(kR_WhiteListedButDenied, W_OK);
+    ASSERT_EQ(ret, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | W_OK);
+    ASSERT_EQ(ret, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, X_OK);
+    ASSERT_EQ(ret, -denied_errno);
+    ret = open_broker.Access(kR_WhiteListedButDenied, R_OK | X_OK);
+    ASSERT_EQ(ret, -denied_errno);
+  }
+
+  fd = open_broker.Open(kW_WhiteListed, O_RDONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(kW_WhiteListed, O_WRONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kW_WhiteListed, O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, F_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kW_WhiteListed, R_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, W_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kW_WhiteListed, R_OK | W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kW_WhiteListed, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  fd = open_broker.Open(kRW_WhiteListed, O_RDONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kRW_WhiteListed, O_WRONLY);
+  ASSERT_EQ(fd, -ENOENT);
+  fd = open_broker.Open(kRW_WhiteListed, O_RDWR);
+  ASSERT_EQ(fd, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, F_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, R_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, W_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, R_OK | W_OK);
+  ASSERT_EQ(ret, -ENOENT);
+  ret = open_broker.Access(kRW_WhiteListed, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(kRW_WhiteListed, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  fd = open_broker.Open(k_NotWhitelisted, O_RDONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(k_NotWhitelisted, O_WRONLY);
+  ASSERT_EQ(fd, -denied_errno);
+  fd = open_broker.Open(k_NotWhitelisted, O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, F_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, R_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, R_OK | W_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+  ret = open_broker.Access(k_NotWhitelisted, R_OK | X_OK);
+  ASSERT_EQ(ret, -denied_errno);
+
+  // We have some extra sanity check for clearly wrong values.
+  fd = open_broker.Open(kRW_WhiteListed, O_RDONLY | O_WRONLY | O_RDWR);
+  ASSERT_EQ(fd, -denied_errno);
+
+  // It makes no sense to allow O_CREAT in a 2-parameters open. Ensure this
+  // is denied.
+  fd = open_broker.Open(kRW_WhiteListed, O_RDWR | O_CREAT);
+  ASSERT_EQ(fd, -denied_errno);
+}
+
+// Run the same thing twice. The second time, we make sure that no security
+// check is performed on the client.
+TEST(BrokerProcess, OpenFilePermsWithClientCheck) {
+  TestOpenFilePerms(true /* fast_check_in_client */, EPERM);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) {
+  TestOpenFilePerms(false /* fast_check_in_client */, EPERM);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+// Run the same twice again, but with ENOENT instead of EPERM.
+TEST(BrokerProcess, OpenFilePermsWithClientCheckNoEnt) {
+  TestOpenFilePerms(true /* fast_check_in_client */, ENOENT);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenOpenFilePermsNoClientCheckNoEnt) {
+  TestOpenFilePerms(false /* fast_check_in_client */, ENOENT);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+void TestBadPaths(bool fast_check_in_client) {
+  const char kFileCpuInfo[] = "/proc/cpuinfo";
+  const char kNotAbsPath[] = "proc/cpuinfo";
+  const char kDotDotStart[] = "/../proc/cpuinfo";
+  const char kDotDotMiddle[] = "/proc/self/../cpuinfo";
+  const char kDotDotEnd[] = "/proc/..";
+  const char kTrailingSlash[] = "/proc/";
+
+  std::vector<BrokerFilePermission> permissions;
+
+  permissions.push_back(BrokerFilePermission::ReadOnlyRecursive("/proc/"));
+  std::unique_ptr<BrokerProcess> open_broker(
+      new BrokerProcess(EPERM, permissions, fast_check_in_client));
+  ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
+  // Open cpuinfo via the broker.
+  int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY);
+  base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd);
+  ASSERT_GE(cpuinfo_fd, 0);
+
+  int fd = -1;
+  int can_access;
+
+  can_access = open_broker->Access(kNotAbsPath, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kNotAbsPath, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kDotDotStart, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kDotDotStart, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kDotDotMiddle, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kDotDotMiddle, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kDotDotEnd, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kDotDotEnd, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+
+  can_access = open_broker->Access(kTrailingSlash, R_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  fd = open_broker->Open(kTrailingSlash, O_RDONLY);
+  ASSERT_EQ(fd, -EPERM);
+}
+
+TEST(BrokerProcess, BadPathsClientCheck) {
+  TestBadPaths(true /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, BadPathsNoClientCheck) {
+  TestBadPaths(false /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+void TestOpenCpuinfo(bool fast_check_in_client, bool recursive) {
+  const char kFileCpuInfo[] = "/proc/cpuinfo";
+  const char kDirProc[] = "/proc/";
+
+  std::vector<BrokerFilePermission> permissions;
+  if (recursive)
+    permissions.push_back(BrokerFilePermission::ReadOnlyRecursive(kDirProc));
+  else
+    permissions.push_back(BrokerFilePermission::ReadOnly(kFileCpuInfo));
+
+  std::unique_ptr<BrokerProcess> open_broker(
+      new BrokerProcess(EPERM, permissions, fast_check_in_client));
+  ASSERT_TRUE(open_broker->Init(base::Bind(&NoOpCallback)));
+
+  int fd = -1;
+  fd = open_broker->Open(kFileCpuInfo, O_RDWR);
+  base::ScopedFD fd_closer(fd);
+  ASSERT_EQ(fd, -EPERM);
+
+  // Check we can read /proc/cpuinfo.
+  int can_access = open_broker->Access(kFileCpuInfo, R_OK);
+  ASSERT_EQ(can_access, 0);
+  can_access = open_broker->Access(kFileCpuInfo, W_OK);
+  ASSERT_EQ(can_access, -EPERM);
+  // Check we can not write /proc/cpuinfo.
+
+  // Open cpuinfo via the broker.
+  int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY);
+  base::ScopedFD cpuinfo_fd_closer(cpuinfo_fd);
+  ASSERT_GE(cpuinfo_fd, 0);
+  char buf[3];
+  memset(buf, 0, sizeof(buf));
+  int read_len1 = read(cpuinfo_fd, buf, sizeof(buf));
+  ASSERT_GT(read_len1, 0);
+
+  // Open cpuinfo directly.
+  int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY);
+  base::ScopedFD cpuinfo_fd2_closer(cpuinfo_fd2);
+  ASSERT_GE(cpuinfo_fd2, 0);
+  char buf2[3];
+  memset(buf2, 1, sizeof(buf2));
+  int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2));
+  ASSERT_GT(read_len1, 0);
+
+  // The following is not guaranteed true, but will be in practice.
+  ASSERT_EQ(read_len1, read_len2);
+  // Compare the cpuinfo as returned by the broker with the one we opened
+  // ourselves.
+  ASSERT_EQ(memcmp(buf, buf2, read_len1), 0);
+
+  ASSERT_TRUE(TestUtils::CurrentProcessHasChildren());
+  open_broker.reset();
+  ASSERT_FALSE(TestUtils::CurrentProcessHasChildren());
+}
+
+// Run this test 4 times. With and without the check in client
+// and using a recursive path.
+TEST(BrokerProcess, OpenCpuinfoWithClientCheck) {
+  TestOpenCpuinfo(true /* fast_check_in_client */, false /* not recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenCpuinfoNoClientCheck) {
+  TestOpenCpuinfo(false /* fast_check_in_client */, false /* not recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenCpuinfoWithClientCheckRecursive) {
+  TestOpenCpuinfo(true /* fast_check_in_client */, true /* recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenCpuinfoNoClientCheckRecursive) {
+  TestOpenCpuinfo(false /* fast_check_in_client */, true /* recursive */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenFileRW) {
+  ScopedTemporaryFile tempfile;
+  const char* tempfile_name = tempfile.full_file_name();
+
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadWrite(tempfile_name));
+
+  BrokerProcess open_broker(EPERM, permissions);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  // Check we can access that file with read or write.
+  int can_access = open_broker.Access(tempfile_name, R_OK | W_OK);
+  ASSERT_EQ(can_access, 0);
+
+  int tempfile2 = -1;
+  tempfile2 = open_broker.Open(tempfile_name, O_RDWR);
+  ASSERT_GE(tempfile2, 0);
+
+  // Write to the descriptor opened by the broker.
+  char test_text[] = "TESTTESTTEST";
+  ssize_t len = write(tempfile2, test_text, sizeof(test_text));
+  ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
+
+  // Read back from the original file descriptor what we wrote through
+  // the descriptor provided by the broker.
+  char buf[1024];
+  len = read(tempfile.fd(), buf, sizeof(buf));
+
+  ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text)));
+  ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0);
+
+  ASSERT_EQ(close(tempfile2), 0);
+}
+
+// SANDBOX_TEST because the process could die with a SIGPIPE
+// and we want this to happen in a subprocess.
+SANDBOX_TEST(BrokerProcess, BrokerDied) {
+  const char kCpuInfo[] = "/proc/cpuinfo";
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo));
+
+  BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */,
+                            true /* quiet_failures_for_tests */);
+  SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
+  const pid_t broker_pid = open_broker.broker_pid();
+  SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0);
+
+  // Now we check that the broker has been signaled, but do not reap it.
+  siginfo_t process_info;
+  SANDBOX_ASSERT(HANDLE_EINTR(waitid(
+                     P_PID, broker_pid, &process_info, WEXITED | WNOWAIT)) ==
+                 0);
+  SANDBOX_ASSERT(broker_pid == process_info.si_pid);
+  SANDBOX_ASSERT(CLD_KILLED == process_info.si_code);
+  SANDBOX_ASSERT(SIGKILL == process_info.si_status);
+
+  // Check that doing Open with a dead broker won't SIGPIPE us.
+  SANDBOX_ASSERT(open_broker.Open(kCpuInfo, O_RDONLY) == -ENOMEM);
+  SANDBOX_ASSERT(open_broker.Access(kCpuInfo, O_RDONLY) == -ENOMEM);
+}
+
+void TestOpenComplexFlags(bool fast_check_in_client) {
+  const char kCpuInfo[] = "/proc/cpuinfo";
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo));
+
+  BrokerProcess open_broker(EPERM, permissions, fast_check_in_client);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+  // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK.
+  int fd = -1;
+  int ret = 0;
+  fd = open_broker.Open(kCpuInfo, O_RDONLY);
+  ASSERT_GE(fd, 0);
+  ret = fcntl(fd, F_GETFL);
+  ASSERT_NE(-1, ret);
+  // The descriptor shouldn't have the O_CLOEXEC attribute, nor O_NONBLOCK.
+  ASSERT_EQ(0, ret & (O_CLOEXEC | O_NONBLOCK));
+  ASSERT_EQ(0, close(fd));
+
+  fd = open_broker.Open(kCpuInfo, O_RDONLY | O_CLOEXEC);
+  ASSERT_GE(fd, 0);
+  ret = fcntl(fd, F_GETFD);
+  ASSERT_NE(-1, ret);
+  // Important: use F_GETFD, not F_GETFL. The O_CLOEXEC flag in F_GETFL
+  // is actually not used by the kernel.
+  ASSERT_TRUE(FD_CLOEXEC & ret);
+  ASSERT_EQ(0, close(fd));
+
+  fd = open_broker.Open(kCpuInfo, O_RDONLY | O_NONBLOCK);
+  ASSERT_GE(fd, 0);
+  ret = fcntl(fd, F_GETFL);
+  ASSERT_NE(-1, ret);
+  ASSERT_TRUE(O_NONBLOCK & ret);
+  ASSERT_EQ(0, close(fd));
+}
+
+TEST(BrokerProcess, OpenComplexFlagsWithClientCheck) {
+  TestOpenComplexFlags(true /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+TEST(BrokerProcess, OpenComplexFlagsNoClientCheck) {
+  TestOpenComplexFlags(false /* fast_check_in_client */);
+  // Don't do anything here, so that ASSERT works in the subfunction as
+  // expected.
+}
+
+#if defined(OS_LINUX)
+// Flaky on Linux NG bots: https://crbug.com/595199.
+#define MAYBE_RecvMsgDescriptorLeak DISABLED_RecvMsgDescriptorLeak
+#else
+#define MAYBE_RecvMsgDescriptorLeak RecvMsgDescriptorLeak
+#endif
+
+// We need to allow noise because the broker will log when it receives our
+// bogus IPCs.
+SANDBOX_TEST_ALLOW_NOISE(BrokerProcess, MAYBE_RecvMsgDescriptorLeak) {
+  // Android creates a socket on first use of the LOG call.
+  // We need to ensure this socket is open before we
+  // begin the test.
+  LOG(INFO) << "Ensure Android LOG socket is allocated";
+
+  // Find the four lowest available file descriptors.
+  int available_fds[4];
+  SANDBOX_ASSERT(0 == pipe(available_fds));
+  SANDBOX_ASSERT(0 == pipe(available_fds + 2));
+
+  // Save one FD to send to the broker later, and close the others.
+  base::ScopedFD message_fd(available_fds[0]);
+  for (size_t i = 1; i < arraysize(available_fds); i++) {
+    SANDBOX_ASSERT(0 == IGNORE_EINTR(close(available_fds[i])));
+  }
+
+  // Lower our file descriptor limit to just allow three more file descriptors
+  // to be allocated.  (N.B., RLIMIT_NOFILE doesn't limit the number of file
+  // descriptors a process can have: it only limits the highest value that can
+  // be assigned to newly-created descriptors allocated by the process.)
+  const rlim_t fd_limit =
+      1 +
+      *std::max_element(available_fds,
+                        available_fds + arraysize(available_fds));
+
+  // Valgrind doesn't allow changing the hard descriptor limit, so we only
+  // change the soft descriptor limit here.
+  struct rlimit rlim;
+  SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim));
+  SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur);
+  rlim.rlim_cur = fd_limit;
+  SANDBOX_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim));
+
+  static const char kCpuInfo[] = "/proc/cpuinfo";
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly(kCpuInfo));
+
+  BrokerProcess open_broker(EPERM, permissions);
+  SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker);
+  SANDBOX_ASSERT(ipc_fd >= 0);
+
+  static const char kBogus[] = "not a pickle";
+  std::vector<int> fds;
+  fds.push_back(message_fd.get());
+
+  // The broker process should only have a couple spare file descriptors
+  // available, but for good measure we send it fd_limit bogus IPCs anyway.
+  for (rlim_t i = 0; i < fd_limit; ++i) {
+    SANDBOX_ASSERT(
+        base::UnixDomainSocket::SendMsg(ipc_fd, kBogus, sizeof(kBogus), fds));
+  }
+
+  const int fd = open_broker.Open(kCpuInfo, O_RDONLY);
+  SANDBOX_ASSERT(fd >= 0);
+  SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd)));
+}
+
+bool CloseFD(int fd) {
+  PCHECK(0 == IGNORE_EINTR(close(fd)));
+  return true;
+}
+
+// Return true if the other end of the |reader| pipe was closed,
+// false if |timeout_in_seconds| was reached or another event
+// or error occured.
+bool WaitForClosedPipeWriter(int reader, int timeout_in_ms) {
+  struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0};
+  const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms));
+  if (1 == num_events && poll_fd.revents | POLLHUP)
+    return true;
+  return false;
+}
+
+// Closing the broker client's IPC channel should terminate the broker
+// process.
+TEST(BrokerProcess, BrokerDiesOnClosedChannel) {
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadOnly("/proc/cpuinfo"));
+
+  // Get the writing end of a pipe into the broker (child) process so
+  // that we can reliably detect when it dies.
+  int lifeline_fds[2];
+  PCHECK(0 == pipe(lifeline_fds));
+
+  BrokerProcess open_broker(EPERM, permissions, true /* fast_check_in_client */,
+                            false /* quiet_failures_for_tests */);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0])));
+  // Make sure the writing end only exists in the broker process.
+  CloseFD(lifeline_fds[1]);
+  base::ScopedFD reader(lifeline_fds[0]);
+
+  const pid_t broker_pid = open_broker.broker_pid();
+
+  // This should cause the broker process to exit.
+  BrokerProcessTestHelper::CloseChannel(&open_broker);
+
+  const int kTimeoutInMilliseconds = 5000;
+  const bool broker_lifeline_closed =
+      WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds);
+  // If the broker exited, its lifeline fd should be closed.
+  ASSERT_TRUE(broker_lifeline_closed);
+  // Now check that the broker has exited, but do not reap it.
+  siginfo_t process_info;
+  ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info,
+                                   WEXITED | WNOWAIT)));
+  EXPECT_EQ(broker_pid, process_info.si_pid);
+  EXPECT_EQ(CLD_EXITED, process_info.si_code);
+  EXPECT_EQ(1, process_info.si_status);
+}
+
+TEST(BrokerProcess, CreateFile) {
+  std::string temp_str;
+  {
+    ScopedTemporaryFile tmp_file;
+    temp_str = tmp_file.full_file_name();
+  }
+  const char* tempfile_name = temp_str.c_str();
+
+  std::vector<BrokerFilePermission> permissions;
+  permissions.push_back(BrokerFilePermission::ReadWriteCreate(tempfile_name));
+
+  BrokerProcess open_broker(EPERM, permissions);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&NoOpCallback)));
+
+  int fd = -1;
+
+  // Try without O_EXCL
+  fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT);
+  ASSERT_EQ(fd, -EPERM);
+
+  const char kTestText[] = "TESTTESTTEST";
+  // Create a file
+  fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL);
+  ASSERT_GE(fd, 0);
+  {
+    base::ScopedFD scoped_fd(fd);
+
+    // Confirm fail if file exists
+    int bad_fd = open_broker.Open(tempfile_name, O_RDWR | O_CREAT | O_EXCL);
+    ASSERT_EQ(bad_fd, -EEXIST);
+
+    // Write to the descriptor opened by the broker.
+
+    ssize_t len = HANDLE_EINTR(write(fd, kTestText, sizeof(kTestText)));
+    ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText)));
+  }
+
+  int fd_check = open(tempfile_name, O_RDONLY);
+  ASSERT_GE(fd_check, 0);
+  {
+    base::ScopedFD scoped_fd(fd_check);
+    char buf[1024];
+    ssize_t len = HANDLE_EINTR(read(fd_check, buf, sizeof(buf)));
+
+    ASSERT_EQ(len, static_cast<ssize_t>(sizeof(kTestText)));
+    ASSERT_EQ(memcmp(kTestText, buf, sizeof(kTestText)), 0);
+  }
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/libchrome/sandbox/linux/system_headers/arm64_linux_syscalls.h b/libchrome/sandbox/linux/system_headers/arm64_linux_syscalls.h
new file mode 100644
index 0000000..8acb2d1
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/arm64_linux_syscalls.h
@@ -0,0 +1,1062 @@
+// 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 SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
+
+#include <asm-generic/unistd.h>
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 0
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 1
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 2
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 3
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 4
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 5
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 6
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 7
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 8
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 9
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 10
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 11
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 12
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 13
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 14
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 15
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 16
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 17
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 18
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 19
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 20
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 21
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 22
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 23
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 24
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 25
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 26
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 27
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 28
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 29
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 30
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 31
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 32
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 33
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 34
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 35
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 36
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 37
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 38
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 39
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 40
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 41
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 42
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 43
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 44
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 45
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 46
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 47
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 48
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 49
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 50
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 51
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 52
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 53
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 54
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 55
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 56
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 57
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 58
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 59
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 60
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 61
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 62
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 63
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 64
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 65
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 66
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 67
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 68
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 69
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 70
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 71
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 72
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 73
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 74
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 75
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 76
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 77
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 78
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat 79
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 80
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 81
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 82
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 83
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 84
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 85
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 86
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 87
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 88
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 89
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 90
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 91
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 92
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 93
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 94
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 95
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 96
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 97
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 98
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 99
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 100
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 101
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 102
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 103
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 104
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 105
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 106
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 107
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 108
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 109
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 110
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 111
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 112
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 113
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 114
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 115
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 116
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 117
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 118
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 119
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 120
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 121
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 122
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 123
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 124
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 125
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 126
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 127
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 128
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 129
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 130
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 131
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 132
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 133
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 134
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 135
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 136
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 137
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 138
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 139
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 140
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 141
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 142
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 143
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 144
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 145
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 146
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 147
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 148
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 149
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 150
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 151
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 152
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 153
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 154
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 155
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 156
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 157
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 158
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 159
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 160
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 161
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 162
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 163
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 164
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 165
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 166
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 167
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 168
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 169
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 170
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 171
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 172
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 173
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 174
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 175
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 176
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 177
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 178
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 179
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 180
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 181
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 182
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 183
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 184
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 185
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 186
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 187
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 188
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 189
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 190
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 191
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop 192
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop 193
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 194
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 195
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 196
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 197
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 198
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 199
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 200
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 201
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept 202
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 203
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 204
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 205
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 206
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 207
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 208
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 209
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 210
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 211
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 212
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 213
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 214
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 215
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 216
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 217
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 218
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 219
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 220
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 221
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 222
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 223
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 224
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 225
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 226
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 227
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 228
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 229
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 230
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 231
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 232
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 233
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 234
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 235
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 236
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 237
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 238
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 239
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 240
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 241
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 242
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 243
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 260
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 261
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 262
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 263
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 264
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 265
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 266
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 267
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 268
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 269
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 270
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 271
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 272
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 273
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 274
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 275
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 276
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 277
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 278
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
diff --git a/libchrome/sandbox/linux/system_headers/arm64_linux_ucontext.h b/libchrome/sandbox/linux/system_headers/arm64_linux_ucontext.h
new file mode 100644
index 0000000..48303ba
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/arm64_linux_ucontext.h
@@ -0,0 +1,30 @@
+// 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 SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#include <asm/sigcontext.h>
+#include <signal.h>
+#include <stdint.h>
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef uint64_t greg_t;
+
+struct ucontext_t {
+  unsigned long uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  sigset_t uc_sigmask;
+  /* glibc uses a 1024-bit sigset_t */
+  uint8_t unused[1024 / 8 - sizeof(sigset_t)];
+  /* last for future expansion */
+  struct sigcontext uc_mcontext;
+};
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_UCONTEXT_H_
diff --git a/libchrome/sandbox/linux/system_headers/arm_linux_syscalls.h b/libchrome/sandbox/linux/system_headers/arm_linux_syscalls.h
new file mode 100644
index 0000000..1addd53
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/arm_linux_syscalls.h
@@ -0,0 +1,1418 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's calls.S.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
+
+#if !defined(__arm__) || !defined(__ARM_EABI__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_SYSCALL_BASE)
+// On ARM EABI arch, __NR_SYSCALL_BASE is 0.
+#define __NR_SYSCALL_BASE 0
+#endif
+
+// This syscall list has holes, because ARM EABI makes some syscalls obsolete.
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_SYSCALL_BASE+0)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_SYSCALL_BASE+1)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_SYSCALL_BASE+2)
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_SYSCALL_BASE+3)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_SYSCALL_BASE+4)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_SYSCALL_BASE+5)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_SYSCALL_BASE+6)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_SYSCALL_BASE+8)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_SYSCALL_BASE+9)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_SYSCALL_BASE+10)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_SYSCALL_BASE+11)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_SYSCALL_BASE+12)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_SYSCALL_BASE+14)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_SYSCALL_BASE+15)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_SYSCALL_BASE+16)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_SYSCALL_BASE+19)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_SYSCALL_BASE+20)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_SYSCALL_BASE+21)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_SYSCALL_BASE+23)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_SYSCALL_BASE+24)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_SYSCALL_BASE+26)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_SYSCALL_BASE+29)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_SYSCALL_BASE+33)
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice (__NR_SYSCALL_BASE+34)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_SYSCALL_BASE+36)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_SYSCALL_BASE+37)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_SYSCALL_BASE+38)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_SYSCALL_BASE+39)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_SYSCALL_BASE+40)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_SYSCALL_BASE+41)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_SYSCALL_BASE+42)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_SYSCALL_BASE+43)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_SYSCALL_BASE+45)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_SYSCALL_BASE+46)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_SYSCALL_BASE+47)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_SYSCALL_BASE+49)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_SYSCALL_BASE+50)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_SYSCALL_BASE+51)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_SYSCALL_BASE+52)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_SYSCALL_BASE+54)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_SYSCALL_BASE+55)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_SYSCALL_BASE+57)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_SYSCALL_BASE+60)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_SYSCALL_BASE+61)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_SYSCALL_BASE+62)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_SYSCALL_BASE+63)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_SYSCALL_BASE+64)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_SYSCALL_BASE+65)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_SYSCALL_BASE+66)
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction (__NR_SYSCALL_BASE+67)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_SYSCALL_BASE+70)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_SYSCALL_BASE+71)
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend (__NR_SYSCALL_BASE+72)
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending (__NR_SYSCALL_BASE+73)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_SYSCALL_BASE+74)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_SYSCALL_BASE+75)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_SYSCALL_BASE+77)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_SYSCALL_BASE+78)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_SYSCALL_BASE+79)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_SYSCALL_BASE+80)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_SYSCALL_BASE+81)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_SYSCALL_BASE+83)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_SYSCALL_BASE+85)
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib (__NR_SYSCALL_BASE+86)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_SYSCALL_BASE+87)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_SYSCALL_BASE+88)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_SYSCALL_BASE+91)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_SYSCALL_BASE+92)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_SYSCALL_BASE+93)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_SYSCALL_BASE+94)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_SYSCALL_BASE+95)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_SYSCALL_BASE+96)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_SYSCALL_BASE+97)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_SYSCALL_BASE+99)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_SYSCALL_BASE+100)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_SYSCALL_BASE+103)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_SYSCALL_BASE+104)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_SYSCALL_BASE+105)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_SYSCALL_BASE+106)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_SYSCALL_BASE+107)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_SYSCALL_BASE+108)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_SYSCALL_BASE+111)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_SYSCALL_BASE+114)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_SYSCALL_BASE+115)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_SYSCALL_BASE+116)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_SYSCALL_BASE+118)
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn (__NR_SYSCALL_BASE+119)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_SYSCALL_BASE+120)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_SYSCALL_BASE+121)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_SYSCALL_BASE+122)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_SYSCALL_BASE+124)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_SYSCALL_BASE+125)
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask (__NR_SYSCALL_BASE+126)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_SYSCALL_BASE+128)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_SYSCALL_BASE+129)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_SYSCALL_BASE+131)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_SYSCALL_BASE+132)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_SYSCALL_BASE+133)
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush (__NR_SYSCALL_BASE+134)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_SYSCALL_BASE+135)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_SYSCALL_BASE+136)
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_SYSCALL_BASE+138)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_SYSCALL_BASE+139)
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek (__NR_SYSCALL_BASE+140)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_SYSCALL_BASE+141)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_SYSCALL_BASE+142)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_SYSCALL_BASE+143)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_SYSCALL_BASE+144)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_SYSCALL_BASE+145)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_SYSCALL_BASE+146)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_SYSCALL_BASE+147)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_SYSCALL_BASE+148)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_SYSCALL_BASE+149)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_SYSCALL_BASE+150)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_SYSCALL_BASE+151)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_SYSCALL_BASE+152)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_SYSCALL_BASE+153)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_SYSCALL_BASE+154)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_SYSCALL_BASE+155)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_SYSCALL_BASE+156)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_SYSCALL_BASE+157)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_SYSCALL_BASE+158)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_SYSCALL_BASE+159)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_SYSCALL_BASE+160)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_SYSCALL_BASE+161)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_SYSCALL_BASE+162)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_SYSCALL_BASE+163)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_SYSCALL_BASE+164)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_SYSCALL_BASE+165)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_SYSCALL_BASE+168)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_SYSCALL_BASE+169)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_SYSCALL_BASE+170)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_SYSCALL_BASE+171)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_SYSCALL_BASE+172)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_SYSCALL_BASE+173)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_SYSCALL_BASE+174)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE+175)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_SYSCALL_BASE+176)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_SYSCALL_BASE+177)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_SYSCALL_BASE+178)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE+179)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_SYSCALL_BASE+180)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_SYSCALL_BASE+181)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_SYSCALL_BASE+182)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_SYSCALL_BASE+183)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_SYSCALL_BASE+184)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_SYSCALL_BASE+185)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_SYSCALL_BASE+186)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_SYSCALL_BASE+187)
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork (__NR_SYSCALL_BASE+190)
+#endif
+
+#if !defined(__NR_ugetrlimit)
+#define __NR_ugetrlimit (__NR_SYSCALL_BASE+191)
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 (__NR_SYSCALL_BASE+192)
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 (__NR_SYSCALL_BASE+193)
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 (__NR_SYSCALL_BASE+194)
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 (__NR_SYSCALL_BASE+195)
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 (__NR_SYSCALL_BASE+196)
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 (__NR_SYSCALL_BASE+197)
+#endif
+
+#if !defined(__NR_lchown32)
+#define __NR_lchown32 (__NR_SYSCALL_BASE+198)
+#endif
+
+#if !defined(__NR_getuid32)
+#define __NR_getuid32 (__NR_SYSCALL_BASE+199)
+#endif
+
+#if !defined(__NR_getgid32)
+#define __NR_getgid32 (__NR_SYSCALL_BASE+200)
+#endif
+
+#if !defined(__NR_geteuid32)
+#define __NR_geteuid32 (__NR_SYSCALL_BASE+201)
+#endif
+
+#if !defined(__NR_getegid32)
+#define __NR_getegid32 (__NR_SYSCALL_BASE+202)
+#endif
+
+#if !defined(__NR_setreuid32)
+#define __NR_setreuid32 (__NR_SYSCALL_BASE+203)
+#endif
+
+#if !defined(__NR_setregid32)
+#define __NR_setregid32 (__NR_SYSCALL_BASE+204)
+#endif
+
+#if !defined(__NR_getgroups32)
+#define __NR_getgroups32 (__NR_SYSCALL_BASE+205)
+#endif
+
+#if !defined(__NR_setgroups32)
+#define __NR_setgroups32 (__NR_SYSCALL_BASE+206)
+#endif
+
+#if !defined(__NR_fchown32)
+#define __NR_fchown32 (__NR_SYSCALL_BASE+207)
+#endif
+
+#if !defined(__NR_setresuid32)
+#define __NR_setresuid32 (__NR_SYSCALL_BASE+208)
+#endif
+
+#if !defined(__NR_getresuid32)
+#define __NR_getresuid32 (__NR_SYSCALL_BASE+209)
+#endif
+
+#if !defined(__NR_setresgid32)
+#define __NR_setresgid32 (__NR_SYSCALL_BASE+210)
+#endif
+
+#if !defined(__NR_getresgid32)
+#define __NR_getresgid32 (__NR_SYSCALL_BASE+211)
+#endif
+
+#if !defined(__NR_chown32)
+#define __NR_chown32 (__NR_SYSCALL_BASE+212)
+#endif
+
+#if !defined(__NR_setuid32)
+#define __NR_setuid32 (__NR_SYSCALL_BASE+213)
+#endif
+
+#if !defined(__NR_setgid32)
+#define __NR_setgid32 (__NR_SYSCALL_BASE+214)
+#endif
+
+#if !defined(__NR_setfsuid32)
+#define __NR_setfsuid32 (__NR_SYSCALL_BASE+215)
+#endif
+
+#if !defined(__NR_setfsgid32)
+#define __NR_setfsgid32 (__NR_SYSCALL_BASE+216)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_SYSCALL_BASE+217)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_SYSCALL_BASE+218)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_SYSCALL_BASE+219)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_SYSCALL_BASE+220)
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 (__NR_SYSCALL_BASE+221)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_SYSCALL_BASE+224)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_SYSCALL_BASE+225)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_SYSCALL_BASE+226)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_SYSCALL_BASE+227)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_SYSCALL_BASE+228)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_SYSCALL_BASE+229)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_SYSCALL_BASE+230)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_SYSCALL_BASE+231)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_SYSCALL_BASE+232)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_SYSCALL_BASE+233)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_SYSCALL_BASE+234)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_SYSCALL_BASE+235)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_SYSCALL_BASE+236)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_SYSCALL_BASE+237)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_SYSCALL_BASE+238)
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 (__NR_SYSCALL_BASE+239)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_SYSCALL_BASE+240)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_SYSCALL_BASE+241)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_SYSCALL_BASE+242)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_SYSCALL_BASE+243)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_SYSCALL_BASE+244)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_SYSCALL_BASE+245)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_SYSCALL_BASE+246)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_SYSCALL_BASE+247)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_SYSCALL_BASE+248)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_SYSCALL_BASE+249)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_SYSCALL_BASE+250)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_SYSCALL_BASE+251)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_SYSCALL_BASE+252)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_SYSCALL_BASE+253)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_SYSCALL_BASE+256)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_SYSCALL_BASE+257)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_SYSCALL_BASE+258)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_SYSCALL_BASE+259)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_SYSCALL_BASE+260)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_SYSCALL_BASE+261)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_SYSCALL_BASE+262)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_SYSCALL_BASE+263)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_SYSCALL_BASE+264)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_SYSCALL_BASE+265)
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 (__NR_SYSCALL_BASE+266)
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 (__NR_SYSCALL_BASE+267)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_SYSCALL_BASE+268)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_SYSCALL_BASE+269)
+#endif
+
+#if !defined(__NR_arm_fadvise64_64)
+#define __NR_arm_fadvise64_64 (__NR_SYSCALL_BASE+270)
+#endif
+
+#if !defined(__NR_pciconfig_iobase)
+#define __NR_pciconfig_iobase (__NR_SYSCALL_BASE+271)
+#endif
+
+#if !defined(__NR_pciconfig_read)
+#define __NR_pciconfig_read (__NR_SYSCALL_BASE+272)
+#endif
+
+#if !defined(__NR_pciconfig_write)
+#define __NR_pciconfig_write (__NR_SYSCALL_BASE+273)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_SYSCALL_BASE+274)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_SYSCALL_BASE+275)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_SYSCALL_BASE+276)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_SYSCALL_BASE+277)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_SYSCALL_BASE+278)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_SYSCALL_BASE+279)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_SYSCALL_BASE+280)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_SYSCALL_BASE+281)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_SYSCALL_BASE+282)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_SYSCALL_BASE+283)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_SYSCALL_BASE+284)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_SYSCALL_BASE+285)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_SYSCALL_BASE+286)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_SYSCALL_BASE+287)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_SYSCALL_BASE+288)
+#endif
+
+#if !defined(__NR_send)
+#define __NR_send (__NR_SYSCALL_BASE+289)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_SYSCALL_BASE+290)
+#endif
+
+#if !defined(__NR_recv)
+#define __NR_recv (__NR_SYSCALL_BASE+291)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_SYSCALL_BASE+292)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_SYSCALL_BASE+293)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_SYSCALL_BASE+294)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_SYSCALL_BASE+295)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_SYSCALL_BASE+296)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_SYSCALL_BASE+297)
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop (__NR_SYSCALL_BASE+298)
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget (__NR_SYSCALL_BASE+299)
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl (__NR_SYSCALL_BASE+300)
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd (__NR_SYSCALL_BASE+301)
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv (__NR_SYSCALL_BASE+302)
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget (__NR_SYSCALL_BASE+303)
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl (__NR_SYSCALL_BASE+304)
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat (__NR_SYSCALL_BASE+305)
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt (__NR_SYSCALL_BASE+306)
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget (__NR_SYSCALL_BASE+307)
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl (__NR_SYSCALL_BASE+308)
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_SYSCALL_BASE+309)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_SYSCALL_BASE+310)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_SYSCALL_BASE+311)
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop (__NR_SYSCALL_BASE+312)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_SYSCALL_BASE+313)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_SYSCALL_BASE+314)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_SYSCALL_BASE+315)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_SYSCALL_BASE+316)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_SYSCALL_BASE+319)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_SYSCALL_BASE+320)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_SYSCALL_BASE+321)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_SYSCALL_BASE+322)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_SYSCALL_BASE+323)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_SYSCALL_BASE+324)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_SYSCALL_BASE+325)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_SYSCALL_BASE+326)
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 (__NR_SYSCALL_BASE+327)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_SYSCALL_BASE+328)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_SYSCALL_BASE+329)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_SYSCALL_BASE+330)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_SYSCALL_BASE+331)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_SYSCALL_BASE+332)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_SYSCALL_BASE+333)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_SYSCALL_BASE+334)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_SYSCALL_BASE+335)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_SYSCALL_BASE+336)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_SYSCALL_BASE+337)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_SYSCALL_BASE+338)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_SYSCALL_BASE+339)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_SYSCALL_BASE+340)
+#endif
+
+#if !defined(__NR_arm_sync_file_range)
+#define __NR_arm_sync_file_range (__NR_SYSCALL_BASE+341)
+#endif
+
+#if !defined(__NR_sync_file_range2)
+#define __NR_sync_file_range2 (__NR_SYSCALL_BASE+341)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_SYSCALL_BASE+342)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_SYSCALL_BASE+343)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_SYSCALL_BASE+344)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_SYSCALL_BASE+345)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_SYSCALL_BASE+346)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_SYSCALL_BASE+347)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_SYSCALL_BASE+348)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_SYSCALL_BASE+349)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_SYSCALL_BASE+350)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_SYSCALL_BASE+351)
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate (__NR_SYSCALL_BASE+352)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_SYSCALL_BASE+353)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_SYSCALL_BASE+354)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_SYSCALL_BASE+355)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_SYSCALL_BASE+356)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_SYSCALL_BASE+357)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_SYSCALL_BASE+358)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_SYSCALL_BASE+359)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_SYSCALL_BASE+360)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_SYSCALL_BASE+361)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_SYSCALL_BASE+362)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_SYSCALL_BASE+364)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_SYSCALL_BASE+365)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_SYSCALL_BASE+366)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_SYSCALL_BASE+367)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_SYSCALL_BASE+368)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_SYSCALL_BASE+369)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_SYSCALL_BASE+370)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_SYSCALL_BASE+371)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_SYSCALL_BASE+372)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_SYSCALL_BASE+373)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_SYSCALL_BASE+374)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_SYSCALL_BASE+375)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_SYSCALL_BASE+378)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_SYSCALL_BASE+379)
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 (__NR_SYSCALL_BASE+382)
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp (__NR_SYSCALL_BASE+383)
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom (__NR_SYSCALL_BASE+384)
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create (__NR_SYSCALL_BASE+385)
+#endif
+
+// ARM private syscalls.
+#if !defined(__ARM_NR_BASE)
+#define __ARM_NR_BASE (__NR_SYSCALL_BASE + 0xF0000)
+#endif
+
+#if !defined(__ARM_NR_breakpoint)
+#define __ARM_NR_breakpoint (__ARM_NR_BASE+1)
+#endif
+
+#if !defined(__ARM_NR_cacheflush)
+#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+#endif
+
+#if !defined(__ARM_NR_usr26)
+#define __ARM_NR_usr26 (__ARM_NR_BASE+3)
+#endif
+
+#if !defined(__ARM_NR_usr32)
+#define __ARM_NR_usr32 (__ARM_NR_BASE+4)
+#endif
+
+#if !defined(__ARM_NR_set_tls)
+#define __ARM_NR_set_tls (__ARM_NR_BASE+5)
+#endif
+
+// ARM kernel private syscall.
+#if !defined(__ARM_NR_cmpxchg)
+#define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
diff --git a/libchrome/sandbox/linux/system_headers/arm_linux_ucontext.h b/libchrome/sandbox/linux/system_headers/arm_linux_ucontext.h
new file mode 100644
index 0000000..35208fa
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/arm_linux_ucontext.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
+
+#include <stddef.h>
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#if !defined(__native_client_nonsfi__)
+#include <asm/sigcontext.h>
+#else
+// In PNaCl toolchain, sigcontext and stack_t is not defined. So here declare
+// them.
+struct sigcontext {
+  unsigned long trap_no;
+  unsigned long error_code;
+  unsigned long oldmask;
+  unsigned long arm_r0;
+  unsigned long arm_r1;
+  unsigned long arm_r2;
+  unsigned long arm_r3;
+  unsigned long arm_r4;
+  unsigned long arm_r5;
+  unsigned long arm_r6;
+  unsigned long arm_r7;
+  unsigned long arm_r8;
+  unsigned long arm_r9;
+  unsigned long arm_r10;
+  unsigned long arm_fp;
+  unsigned long arm_ip;
+  unsigned long arm_sp;
+  unsigned long arm_lr;
+  unsigned long arm_pc;
+  unsigned long arm_cpsr;
+  unsigned long fault_address;
+};
+
+typedef struct sigaltstack {
+  void* ss_sp;
+  int ss_flags;
+  size_t ss_size;
+} stack_t;
+
+#endif
+
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef unsigned long greg_t;
+
+// typedef unsigned long sigset_t;
+typedef struct ucontext {
+  unsigned long uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  struct sigcontext uc_mcontext;
+  sigset_t uc_sigmask;
+  /* Allow for uc_sigmask growth.  Glibc uses a 1024-bit sigset_t.  */
+  int __not_used[32 - (sizeof(sigset_t) / sizeof(int))];
+  /* Last for extensibility.  Eight byte aligned because some
+     coprocessors require eight byte alignment.  */
+  unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
diff --git a/libchrome/sandbox/linux/system_headers/capability.h b/libchrome/sandbox/linux/system_headers/capability.h
new file mode 100644
index 0000000..f91fcf7
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/capability.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 SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
+
+#include <stdint.h>
+
+// The following macros are taken from linux/capability.h.
+// We only support capability version 3, which was introduced in Linux 2.6.26.
+#ifndef _LINUX_CAPABILITY_VERSION_3
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#endif
+#ifndef _LINUX_CAPABILITY_U32S_3
+#define _LINUX_CAPABILITY_U32S_3 2
+#endif
+#ifndef CAP_TO_INDEX
+#define CAP_TO_INDEX(x) ((x) >> 5)  // 1 << 5 == bits in __u32
+#endif
+#ifndef CAP_TO_MASK
+#define CAP_TO_MASK(x) (1 << ((x) & 31))  // mask for indexed __u32
+#endif
+#ifndef CAP_SYS_CHROOT
+#define CAP_SYS_CHROOT 18
+#endif
+#ifndef CAP_SYS_ADMIN
+#define CAP_SYS_ADMIN 21
+#endif
+
+struct cap_hdr {
+  uint32_t version;
+  int pid;
+};
+
+struct cap_data {
+  uint32_t effective;
+  uint32_t permitted;
+  uint32_t inheritable;
+};
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
diff --git a/libchrome/sandbox/linux/system_headers/i386_linux_ucontext.h b/libchrome/sandbox/linux/system_headers/i386_linux_ucontext.h
new file mode 100644
index 0000000..f438033
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/i386_linux_ucontext.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 SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// We do something compatible with glibc. Hopefully, at some point Android will
+// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
+// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
+// except we do use sigset_t for uc_sigmask instead of a custom type.
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#if !defined(__native_client_nonsfi__)
+#include <asm/sigcontext.h>
+#else
+// In PNaCl toolchain, sigcontext is not defined. So here declare it.
+typedef struct sigaltstack {
+  void* ss_sp;
+  int ss_flags;
+  size_t ss_size;
+} stack_t;
+#endif
+
+/* 80-bit floating-point register */
+struct _libc_fpreg {
+  unsigned short significand[4];
+  unsigned short exponent;
+};
+
+/* Simple floating-point state, see FNSTENV instruction */
+struct _libc_fpstate {
+  unsigned long cw;
+  unsigned long sw;
+  unsigned long tag;
+  unsigned long ipoff;
+  unsigned long cssel;
+  unsigned long dataoff;
+  unsigned long datasel;
+  struct _libc_fpreg _st[8];
+  unsigned long status;
+};
+
+typedef uint32_t greg_t;
+
+typedef struct {
+  uint32_t gregs[19];
+  struct _libc_fpstate* fpregs;
+  uint32_t oldmask;
+  uint32_t cr2;
+} mcontext_t;
+
+enum {
+  REG_GS = 0,
+  REG_FS,
+  REG_ES,
+  REG_DS,
+  REG_EDI,
+  REG_ESI,
+  REG_EBP,
+  REG_ESP,
+  REG_EBX,
+  REG_EDX,
+  REG_ECX,
+  REG_EAX,
+  REG_TRAPNO,
+  REG_ERR,
+  REG_EIP,
+  REG_CS,
+  REG_EFL,
+  REG_UESP,
+  REG_SS,
+};
+
+typedef struct ucontext {
+  uint32_t uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  // Android and PNaCl toolchain's sigset_t has only 32 bits, though Linux
+  // ABI requires 64 bits.
+  union {
+    sigset_t uc_sigmask;
+    uint32_t kernel_sigmask[2];
+  };
+  struct _libc_fpstate __fpregs_mem;
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
diff --git a/libchrome/sandbox/linux/system_headers/linux_filter.h b/libchrome/sandbox/linux/system_headers/linux_filter.h
new file mode 100644
index 0000000..b23b6eb
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/linux_filter.h
@@ -0,0 +1,140 @@
+// 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 SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
+
+#include <stdint.h>
+
+// The following structs and macros are taken from linux/filter.h,
+// as some toolchain does not expose them.
+struct sock_filter {
+  uint16_t code;
+  uint8_t jt;
+  uint8_t jf;
+  uint32_t k;
+};
+
+struct sock_fprog {
+  uint16_t len;
+  struct sock_filter *filter;
+};
+
+#ifndef BPF_CLASS
+#define BPF_CLASS(code) ((code) & 0x07)
+#endif
+
+#ifndef BPF_LD
+#define BPF_LD 0x00
+#endif
+
+#ifndef BPF_ALU
+#define BPF_ALU 0x04
+#endif
+
+#ifndef BPF_JMP
+#define BPF_JMP 0x05
+#endif
+
+#ifndef BPF_RET
+#define BPF_RET 0x06
+#endif
+
+#ifndef BPF_SIZE
+#define BPF_SIZE(code) ((code) & 0x18)
+#endif
+
+#ifndef BPF_W
+#define BPF_W 0x00
+#endif
+
+#ifndef BPF_MODE
+#define BPF_MODE(code) ((code) & 0xe0)
+#endif
+
+#ifndef BPF_ABS
+#define BPF_ABS 0x20
+#endif
+
+#ifndef BPF_OP
+#define BPF_OP(code) ((code) & 0xf0)
+#endif
+
+#ifndef BPF_ADD
+#define BPF_ADD 0x00
+#endif
+
+#ifndef BPF_SUB
+#define BPF_SUB 0x10
+#endif
+
+#ifndef BPF_MUL
+#define BPF_MUL 0x20
+#endif
+
+#ifndef BPF_DIV
+#define BPF_DIV 0x30
+#endif
+
+#ifndef BPF_OR
+#define BPF_OR 0x40
+#endif
+
+#ifndef BPF_AND
+#define BPF_AND 0x50
+#endif
+
+#ifndef BPF_LSH
+#define BPF_LSH 0x60
+#endif
+
+#ifndef BPF_RSH
+#define BPF_RSH 0x70
+#endif
+
+#ifndef BPF_NEG
+#define BPF_NEG 0x80
+#endif
+
+#ifndef BPF_MOD
+#define BPF_MOD 0x90
+#endif
+
+#ifndef BPF_XOR
+#define BPF_XOR 0xA0
+#endif
+
+#ifndef BPF_JA
+#define BPF_JA 0x00
+#endif
+
+#ifndef BPF_JEQ
+#define BPF_JEQ 0x10
+#endif
+
+#ifndef BPF_JGT
+#define BPF_JGT 0x20
+#endif
+
+#ifndef BPF_JGE
+#define BPF_JGE 0x30
+#endif
+
+#ifndef BPF_JSET
+#define BPF_JSET 0x40
+#endif
+
+#ifndef BPF_SRC
+#define BPF_SRC(code) ((code) & 0x08)
+#endif
+
+#ifndef BPF_K
+#define BPF_K 0x00
+#endif
+
+#ifndef BPF_MAXINSNS
+#define BPF_MAXINSNS 4096
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
diff --git a/libchrome/sandbox/linux/system_headers/linux_futex.h b/libchrome/sandbox/linux/system_headers/linux_futex.h
new file mode 100644
index 0000000..4e28403
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/linux_futex.h
@@ -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.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
+
+#if !defined(__native_client_nonsfi__)
+#include <linux/futex.h>
+#endif  // !defined(__native_client_nonsfi__)
+
+#if !defined(FUTEX_WAIT)
+#define FUTEX_WAIT 0
+#endif
+
+#if !defined(FUTEX_WAKE)
+#define FUTEX_WAKE 1
+#endif
+
+#if !defined(FUTEX_FD)
+#define FUTEX_FD 2
+#endif
+
+#if !defined(FUTEX_REQUEUE)
+#define FUTEX_REQUEUE 3
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE)
+#define FUTEX_CMP_REQUEUE 4
+#endif
+
+#if !defined(FUTEX_WAKE_OP)
+#define FUTEX_WAKE_OP 5
+#endif
+
+#if !defined(FUTEX_LOCK_PI)
+#define FUTEX_LOCK_PI 6
+#endif
+
+#if !defined(FUTEX_UNLOCK_PI)
+#define FUTEX_UNLOCK_PI 7
+#endif
+
+#if !defined(FUTEX_TRYLOCK_PI)
+#define FUTEX_TRYLOCK_PI 8
+#endif
+
+#if !defined(FUTEX_WAIT_BITSET)
+#define FUTEX_WAIT_BITSET 9
+#endif
+
+#if !defined(FUTEX_WAKE_BITSET)
+#define FUTEX_WAKE_BITSET 10
+#endif
+
+#if !defined(FUTEX_WAIT_REQUEUE_PI)
+#define FUTEX_WAIT_REQUEUE_PI 11
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE_PI)
+#define FUTEX_CMP_REQUEUE_PI 12
+#endif
+
+#if !defined(FUTEX_PRIVATE_FLAG)
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+
+#if !defined FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+
+#if !defined(FUTEX_CMD_MASK)
+#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE_PI_PRIVATE)
+#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | FUTEX_PRIVATE_FLAG)
+#endif
+
+#if !defined(FUTEX_UNLOCK_PI_PRIVATE)
+#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
diff --git a/libchrome/sandbox/linux/system_headers/linux_seccomp.h b/libchrome/sandbox/linux/system_headers/linux_seccomp.h
new file mode 100644
index 0000000..3deb3d2
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/linux_seccomp.h
@@ -0,0 +1,107 @@
+// 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 SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
+
+// The Seccomp2 kernel ABI is not part of older versions of glibc.
+// As we can't break compilation with these versions of the library,
+// we explicitly define all missing symbols.
+// If we ever decide that we can now rely on system headers, the following
+// include files should be enabled:
+// #include <linux/audit.h>
+// #include <linux/seccomp.h>
+
+// For audit.h
+#ifndef EM_ARM
+#define EM_ARM    40
+#endif
+#ifndef EM_386
+#define EM_386    3
+#endif
+#ifndef EM_X86_64
+#define EM_X86_64 62
+#endif
+#ifndef EM_MIPS
+#define EM_MIPS   8
+#endif
+#ifndef EM_AARCH64
+#define EM_AARCH64 183
+#endif
+
+#ifndef __AUDIT_ARCH_64BIT
+#define __AUDIT_ARCH_64BIT 0x80000000
+#endif
+#ifndef __AUDIT_ARCH_LE
+#define __AUDIT_ARCH_LE    0x40000000
+#endif
+#ifndef AUDIT_ARCH_ARM
+#define AUDIT_ARCH_ARM    (EM_ARM|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_I386
+#define AUDIT_ARCH_I386   (EM_386|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_X86_64
+#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_MIPSEL
+#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_AARCH64
+#define AUDIT_ARCH_AARCH64 (EM_AARCH64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
+#endif
+
+// For prctl.h
+#ifndef PR_SET_SECCOMP
+#define PR_SET_SECCOMP               22
+#define PR_GET_SECCOMP               21
+#endif
+#ifndef PR_SET_NO_NEW_PRIVS
+#define PR_SET_NO_NEW_PRIVS          38
+#define PR_GET_NO_NEW_PRIVS          39
+#endif
+#ifndef IPC_64
+#define IPC_64                   0x0100
+#endif
+
+// In order to build will older tool chains, we currently have to avoid
+// including <linux/seccomp.h>. Until that can be fixed (if ever). Rely on
+// our own definitions of the seccomp kernel ABI.
+#ifndef SECCOMP_MODE_FILTER
+#define SECCOMP_MODE_DISABLED         0
+#define SECCOMP_MODE_STRICT           1
+#define SECCOMP_MODE_FILTER           2  // User user-supplied filter
+#endif
+
+#ifndef SECCOMP_SET_MODE_STRICT
+#define SECCOMP_SET_MODE_STRICT 0
+#endif
+#ifndef SECCOMP_SET_MODE_FILTER
+#define SECCOMP_SET_MODE_FILTER 1
+#endif
+#ifndef SECCOMP_FILTER_FLAG_TSYNC
+#define SECCOMP_FILTER_FLAG_TSYNC 1
+#endif
+
+#ifndef SECCOMP_RET_KILL
+// Return values supported for BPF filter programs. Please note that the
+// "illegal" SECCOMP_RET_INVALID is not supported by the kernel, should only
+// ever be used internally, and would result in the kernel killing our process.
+#define SECCOMP_RET_KILL    0x00000000U  // Kill the task immediately
+#define SECCOMP_RET_INVALID 0x00010000U  // Illegal return value
+#define SECCOMP_RET_TRAP    0x00030000U  // Disallow and force a SIGSYS
+#define SECCOMP_RET_ERRNO   0x00050000U  // Returns an errno
+#define SECCOMP_RET_TRACE   0x7ff00000U  // Pass to a tracer or disallow
+#define SECCOMP_RET_ALLOW   0x7fff0000U  // Allow
+#define SECCOMP_RET_ACTION  0xffff0000U  // Masks for the return value
+#define SECCOMP_RET_DATA    0x0000ffffU  //   sections
+#else
+#define SECCOMP_RET_INVALID 0x00010000U  // Illegal return value
+#endif
+
+#ifndef SYS_SECCOMP
+#define SYS_SECCOMP                   1
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
diff --git a/libchrome/sandbox/linux/system_headers/linux_signal.h b/libchrome/sandbox/linux/system_headers/linux_signal.h
new file mode 100644
index 0000000..fb9a47b
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/linux_signal.h
@@ -0,0 +1,146 @@
+// 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 SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
+
+#include <stdint.h>
+
+// NOTE: On some toolchains, signal related ABI is incompatible with Linux's
+// (not undefined, but defined different values and in different memory
+// layouts). So, fill the gap here.
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
+    defined(__aarch64__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 7
+#define LINUX_SIGUSR1 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGUSR2 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGCHLD 17
+#define LINUX_SIGSYS 31
+
+#define LINUX_SIG_BLOCK 0
+#define LINUX_SIG_UNBLOCK 1
+
+#define LINUX_SA_SIGINFO 4
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#elif defined(__mips__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGSYS 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGUSR1 16
+#define LINUX_SIGUSR2 17
+#define LINUX_SIGCHLD 18
+
+#define LINUX_SIG_BLOCK 1
+#define LINUX_SIG_UNBLOCK 2
+
+#define LINUX_SA_SIGINFO 0x00000008
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#else
+#error "Unsupported platform"
+#endif
+
+#if defined(__native_client_nonsfi__)
+#if !defined(__i386__) && !defined(__arm__)
+#error "Unsupported platform"
+#endif
+
+#include <signal.h>
+
+struct LinuxSigInfo {
+  int si_signo;
+  int si_errno;
+  int si_code;
+
+  // Extra data is followed by the |si_code|. The length depends on the
+  // signal number.
+  char _sifields[1];
+};
+
+#include "sandbox/linux/system_headers/linux_ucontext.h"
+
+#else  // !defined(__native_client_nonsfi__)
+
+#include <signal.h>
+
+static_assert(LINUX_SIGHUP == SIGHUP, "LINUX_SIGHUP == SIGHUP");
+static_assert(LINUX_SIGINT == SIGINT, "LINUX_SIGINT == SIGINT");
+static_assert(LINUX_SIGQUIT == SIGQUIT, "LINUX_SIGQUIT == SIGQUIT");
+static_assert(LINUX_SIGABRT == SIGABRT, "LINUX_SIGABRT == SIGABRT");
+static_assert(LINUX_SIGBUS == SIGBUS, "LINUX_SIGBUS == SIGBUS");
+static_assert(LINUX_SIGUSR1 == SIGUSR1, "LINUX_SIGUSR1 == SIGUSR1");
+static_assert(LINUX_SIGSEGV == SIGSEGV, "LINUX_SIGSEGV == SIGSEGV");
+static_assert(LINUX_SIGUSR2 == SIGUSR2, "LINUX_SIGUSR2 == SIGUSR2");
+static_assert(LINUX_SIGPIPE == SIGPIPE, "LINUX_SIGPIPE == SIGPIPE");
+static_assert(LINUX_SIGTERM == SIGTERM, "LINUX_SIGTERM == SIGTERM");
+static_assert(LINUX_SIGCHLD == SIGCHLD, "LINUX_SIGCHLD == SIGCHLD");
+static_assert(LINUX_SIGSYS == SIGSYS, "LINUX_SIGSYS == SIGSYS");
+static_assert(LINUX_SIG_BLOCK == SIG_BLOCK, "LINUX_SIG_BLOCK == SIG_BLOCK");
+static_assert(LINUX_SIG_UNBLOCK == SIG_UNBLOCK,
+              "LINUX_SIG_UNBLOCK == SIG_UNBLOCK");
+static_assert(LINUX_SA_SIGINFO == SA_SIGINFO, "LINUX_SA_SIGINFO == SA_SIGINFO");
+static_assert(LINUX_SA_NODEFER == SA_NODEFER, "LINUX_SA_NODEFER == SA_NODEFER");
+static_assert(LINUX_SA_RESTART == SA_RESTART, "LINUX_SA_RESTART == SA_RESTART");
+static_assert(LINUX_SIG_DFL == SIG_DFL, "LINUX_SIG_DFL == SIG_DFL");
+
+typedef siginfo_t LinuxSigInfo;
+
+#if defined(__ANDROID__)
+// Android's signal.h doesn't define ucontext etc.
+#include "sandbox/linux/system_headers/linux_ucontext.h"
+#endif  // defined(__ANDROID__)
+
+#endif  // !defined(__native_client_nonsfi__)
+
+// struct sigset_t is different size in PNaCl from the Linux's.
+#if defined(__mips__)
+#if !defined(_NSIG_WORDS)
+#define _NSIG_WORDS 4
+#endif
+struct LinuxSigSet {
+  unsigned long sig[_NSIG_WORDS];
+};
+#else
+typedef uint64_t LinuxSigSet;
+#endif
+
+// struct sigaction is different in PNaCl from the Linux's.
+#if defined(__mips__)
+struct LinuxSigAction {
+  unsigned int sa_flags;
+  void (*kernel_handler)(int);
+  LinuxSigSet sa_mask;
+};
+#else
+struct LinuxSigAction {
+  void (*kernel_handler)(int);
+  uint32_t sa_flags;
+  void (*sa_restorer)(void);
+  LinuxSigSet sa_mask;
+};
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
diff --git a/libchrome/sandbox/linux/system_headers/linux_syscalls.h b/libchrome/sandbox/linux/system_headers/linux_syscalls.h
new file mode 100644
index 0000000..2b441e4
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/linux_syscalls.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.
+
+// This header will be kept up to date so that we can compile system-call
+// policies even when system headers are old.
+// System call numbers are accessible through __NR_syscall_name.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+
+#if defined(__x86_64__)
+#include "sandbox/linux/system_headers/x86_64_linux_syscalls.h"
+#endif
+
+#if defined(__i386__)
+#include "sandbox/linux/system_headers/x86_32_linux_syscalls.h"
+#endif
+
+#if defined(__arm__) && defined(__ARM_EABI__)
+#include "sandbox/linux/system_headers/arm_linux_syscalls.h"
+#endif
+
+#if defined(__mips__) && (_MIPS_SIM == _ABIO32)
+#include "sandbox/linux/system_headers/mips_linux_syscalls.h"
+#endif
+
+#if defined(__mips__) && (_MIPS_SIM == _ABI64)
+#include "sandbox/linux/system_headers/mips64_linux_syscalls.h"
+#endif
+
+#if defined(__aarch64__)
+#include "sandbox/linux/system_headers/arm64_linux_syscalls.h"
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+
diff --git a/libchrome/sandbox/linux/system_headers/linux_time.h b/libchrome/sandbox/linux/system_headers/linux_time.h
new file mode 100644
index 0000000..e6c8112
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/linux_time.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 SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_TIME_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_TIME_H_
+
+#include <time.h>
+
+#if !defined(CLOCK_REALTIME_COARSE)
+#define CLOCK_REALTIME_COARSE 5
+#endif
+
+#if !defined(CLOCK_MONOTONIC_COARSE)
+#define CLOCK_MONOTONIC_COARSE 6
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_TIME_H_
diff --git a/libchrome/sandbox/linux/system_headers/linux_ucontext.h b/libchrome/sandbox/linux/system_headers/linux_ucontext.h
new file mode 100644
index 0000000..ea4d8a6
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/linux_ucontext.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 SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
+
+#if defined(__ANDROID__) || defined(__native_client_nonsfi__)
+
+#if defined(__arm__)
+#include "sandbox/linux/system_headers/arm_linux_ucontext.h"
+#elif defined(__i386__)
+#include "sandbox/linux/system_headers/i386_linux_ucontext.h"
+#elif defined(__x86_64__)
+#include "sandbox/linux/system_headers/x86_64_linux_ucontext.h"
+#elif defined(__mips__)
+#include "sandbox/linux/system_headers/mips_linux_ucontext.h"
+#elif defined(__aarch64__)
+#include "sandbox/linux/system_headers/arm64_linux_ucontext.h"
+#else
+#error "No support for your architecture in Android or PNaCl header"
+#endif
+
+#else  // defined(__ANDROID__) || defined(__native_client_nonsfi__)
+#error "The header file included on non Android and non PNaCl."
+#endif  // defined(__ANDROID__) || defined(__native_client_nonsfi__)
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
diff --git a/libchrome/sandbox/linux/system_headers/mips64_linux_syscalls.h b/libchrome/sandbox/linux/system_headers/mips64_linux_syscalls.h
new file mode 100644
index 0000000..d003124
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/mips64_linux_syscalls.h
@@ -0,0 +1,1266 @@
+// 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.
+
+// Generated from the Linux kernel's calls.S.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
+
+#if !defined(__mips__) || (_MIPS_SIM != _ABI64)
+#error "Including header on wrong architecture"
+#endif
+
+// __NR_Linux, is defined in <asm/unistd.h>.
+#include <asm/unistd.h>
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_Linux + 0)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_Linux + 1)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_Linux + 2)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_Linux + 3)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_Linux + 4)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_Linux + 5)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_Linux + 6)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_Linux + 7)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_Linux + 8)
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap (__NR_Linux + 9)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_Linux + 10)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_Linux + 11)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_Linux + 12)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_Linux + 13)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_Linux + 14)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_Linux + 15)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_Linux + 16)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_Linux + 17)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_Linux + 18)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_Linux + 19)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_Linux + 20)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_Linux + 21)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_Linux + 22)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_Linux + 23)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_Linux + 24)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_Linux + 25)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_Linux + 26)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_Linux + 27)
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget (__NR_Linux + 28)
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat (__NR_Linux + 29)
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl (__NR_Linux + 30)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_Linux + 31)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_Linux + 32)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_Linux + 33)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_Linux + 34)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_Linux + 35)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_Linux + 36)
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm (__NR_Linux + 37)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_Linux + 38)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_Linux + 39)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_Linux + 40)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_Linux + 41)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_Linux + 42)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_Linux + 43)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_Linux + 44)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_Linux + 45)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_Linux + 46)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_Linux + 47)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_Linux + 48)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_Linux + 49)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_Linux + 50)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_Linux + 51)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_Linux + 52)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_Linux + 53)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_Linux + 54)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_Linux + 55)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_Linux + 56)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_Linux + 57)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_Linux + 58)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_Linux + 59)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_Linux + 60)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_Linux + 61)
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget (__NR_Linux + 62)
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop (__NR_Linux + 63)
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl (__NR_Linux + 64)
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt (__NR_Linux + 65)
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget (__NR_Linux + 66)
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd (__NR_Linux + 67)
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv (__NR_Linux + 68)
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl (__NR_Linux + 69)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_Linux + 70)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_Linux + 71)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_Linux + 72)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_Linux + 73)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_Linux + 74)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_Linux + 75)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_Linux + 76)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_Linux + 77)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_Linux + 78)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_Linux + 79)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_Linux + 80)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_Linux + 81)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_Linux + 82)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_Linux + 83)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_Linux + 84)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_Linux + 85)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_Linux + 86)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_Linux + 87)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_Linux + 88)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_Linux + 89)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_Linux + 90)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_Linux + 91)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_Linux + 92)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_Linux + 93)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_Linux + 94)
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit (__NR_Linux + 95)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_Linux + 96)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_Linux + 97)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_Linux + 98)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_Linux + 99)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_Linux + 100)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_Linux + 101)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_Linux + 102)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_Linux + 103)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_Linux + 104)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_Linux + 105)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_Linux + 106)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_Linux + 107)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_Linux + 108)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_Linux + 109)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_Linux + 110)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_Linux + 111)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_Linux + 112)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_Linux + 113)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_Linux + 114)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_Linux + 115)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_Linux + 116)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_Linux + 117)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_Linux + 118)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_Linux + 119)
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_Linux + 120)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_Linux + 121)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_Linux + 122)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_Linux + 123)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_Linux + 124)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_Linux + 125)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_Linux + 126)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_Linux + 127)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_Linux + 128)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_Linux + 129)
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime (__NR_Linux + 130)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_Linux + 131)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_Linux + 132)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_Linux + 133)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_Linux + 134)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_Linux + 135)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_Linux + 136)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_Linux + 137)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_Linux + 138)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_Linux + 139)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_Linux + 140)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_Linux + 141)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_Linux + 142)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_Linux + 143)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_Linux + 144)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_Linux + 145)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_Linux + 146)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_Linux + 147)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_Linux + 148)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_Linux + 149)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_Linux + 150)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_Linux + 151)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_Linux + 152)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_Linux + 153)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_Linux + 154)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_Linux + 155)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_Linux + 156)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_Linux + 157)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_Linux + 158)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_Linux + 159)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_Linux + 160)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_Linux + 161)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_Linux + 162)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_Linux + 163)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_Linux + 164)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_Linux + 165)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_Linux + 166)
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module (__NR_Linux + 167)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_Linux + 168)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_Linux + 169)
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms (__NR_Linux + 170)
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module (__NR_Linux + 171)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_Linux + 172)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_Linux + 173)
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg (__NR_Linux + 174)
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg (__NR_Linux + 175)
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall (__NR_Linux + 176)
+#endif
+
+#if !defined(__NR_reserved177)
+#define __NR_reserved177 (__NR_Linux + 177)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_Linux + 178)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_Linux + 179)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_Linux + 180)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_Linux + 181)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_Linux + 182)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_Linux + 183)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_Linux + 184)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_Linux + 185)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_Linux + 186)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_Linux + 187)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_Linux + 188)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_Linux + 189)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_Linux + 190)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_Linux + 191)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_Linux + 192)
+#endif
+
+#if !defined(__NR_reserved193)
+#define __NR_reserved193 (__NR_Linux + 193)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_Linux + 194)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_Linux + 195)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_Linux + 196)
+#endif
+
+#if !defined(__NR_cacheflush)
+#define __NR_cacheflush (__NR_Linux + 197)
+#endif
+
+#if !defined(__NR_cachectl)
+#define __NR_cachectl (__NR_Linux + 198)
+#endif
+
+#if !defined(__NR_sysmips)
+#define __NR_sysmips (__NR_Linux + 199)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_Linux + 200)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_Linux + 201)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_Linux + 202)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_Linux + 203)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_Linux + 204)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_Linux + 205)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_Linux + 206)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_Linux + 207)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_Linux + 208)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_Linux + 209)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_Linux + 210)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_Linux + 211)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_Linux + 212)
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_Linux + 213)
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop (__NR_Linux + 214)
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 (__NR_Linux + 215)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_Linux + 216)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_Linux + 217)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_Linux + 218)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_Linux + 219)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_Linux + 220)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_Linux + 221)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_Linux + 222)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_Linux + 223)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_Linux + 224)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_Linux + 225)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_Linux + 226)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_Linux + 227)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_Linux + 228)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_Linux + 229)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_Linux + 230)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_Linux + 231)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_Linux + 232)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_Linux + 233)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_Linux + 234)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_Linux + 235)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_Linux + 236)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_Linux + 237)
+#endif
+
+/* #define __NR_sys_setaltroot (__NR_Linux + 238) */
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_Linux + 239)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_Linux + 240)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_Linux + 241)
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area (__NR_Linux + 242)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_Linux + 243)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_Linux + 244)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_Linux + 245)
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages (__NR_Linux + 246)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_Linux + 247)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_Linux + 248)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_Linux + 249)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_Linux + 250)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_Linux + 251)
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat (__NR_Linux + 252)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_Linux + 253)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_Linux + 254)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_Linux + 255)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_Linux + 256)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_Linux + 257)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_Linux + 258)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_Linux + 259)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_Linux + 260)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_Linux + 261)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_Linux + 262)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_Linux + 263)
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range (__NR_Linux + 264)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_Linux + 265)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_Linux + 266)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_Linux + 267)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_Linux + 268)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_Linux + 269)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_Linux + 270)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_Linux + 271)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_Linux + 272)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_Linux + 273)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_Linux + 274)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_Linux + 275)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_Linux + 276)
+#endif
+
+#if !defined(__NR_timerfd)
+#define __NR_timerfd (__NR_Linux + 277)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 278)
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate (__NR_Linux + 279)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_Linux + 280)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_Linux + 281)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_Linux + 282)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_Linux + 283)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_Linux + 284)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_Linux + 285)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_Linux + 286)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_Linux + 287)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_Linux + 288)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_Linux + 289)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_Linux + 290)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_Linux + 291)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_Linux + 292)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_Linux + 293)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_Linux + 294)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_Linux + 295)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_Linux + 296)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_Linux + 297)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_Linux + 298)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_Linux + 299)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_Linux + 300)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_Linux + 301)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_Linux + 302)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_Linux + 303)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_Linux + 304)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_Linux + 305)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_Linux + 306)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_Linux + 307)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_Linux + 308)
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr (__NR_Linux + 309)
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr (__NR_Linux + 310)
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 (__NR_Linux + 311)
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp (__NR_Linux + 312)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS64_LINUX_SYSCALLS_H_
diff --git a/libchrome/sandbox/linux/system_headers/mips_linux_syscalls.h b/libchrome/sandbox/linux/system_headers/mips_linux_syscalls.h
new file mode 100644
index 0000000..eb1717a
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/mips_linux_syscalls.h
@@ -0,0 +1,1428 @@
+// 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.
+
+// Generated from the Linux kernel's calls.S.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
+
+#if !defined(__mips__) || (_MIPS_SIM != _ABIO32)
+#error "Including header on wrong architecture"
+#endif
+
+// __NR_Linux, is defined in <asm/unistd.h>.
+#include <asm/unistd.h>
+
+#if !defined(__NR_syscall)
+#define __NR_syscall (__NR_Linux + 0)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_Linux + 1)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_Linux + 2)
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_Linux + 3)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_Linux + 4)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_Linux + 5)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_Linux + 6)
+#endif
+
+#if !defined(__NR_waitpid)
+#define __NR_waitpid (__NR_Linux + 7)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_Linux + 8)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_Linux + 9)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_Linux + 10)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_Linux + 11)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_Linux + 12)
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time (__NR_Linux + 13)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_Linux + 14)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_Linux + 15)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_Linux + 16)
+#endif
+
+#if !defined(__NR_break)
+#define __NR_break (__NR_Linux + 17)
+#endif
+
+#if !defined(__NR_unused18)
+#define __NR_unused18 (__NR_Linux + 18)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_Linux + 19)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_Linux + 20)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_Linux + 21)
+#endif
+
+#if !defined(__NR_umount)
+#define __NR_umount (__NR_Linux + 22)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_Linux + 23)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_Linux + 24)
+#endif
+
+#if !defined(__NR_stime)
+#define __NR_stime (__NR_Linux + 25)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_Linux + 26)
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm (__NR_Linux + 27)
+#endif
+
+#if !defined(__NR_unused28)
+#define __NR_unused28 (__NR_Linux + 28)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_Linux + 29)
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime (__NR_Linux + 30)
+#endif
+
+#if !defined(__NR_stty)
+#define __NR_stty (__NR_Linux + 31)
+#endif
+
+#if !defined(__NR_gtty)
+#define __NR_gtty (__NR_Linux + 32)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_Linux + 33)
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice (__NR_Linux + 34)
+#endif
+
+#if !defined(__NR_ftime)
+#define __NR_ftime (__NR_Linux + 35)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_Linux + 36)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_Linux + 37)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_Linux + 38)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_Linux + 39)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_Linux + 40)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_Linux + 41)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_Linux + 42)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_Linux + 43)
+#endif
+
+#if !defined(__NR_prof)
+#define __NR_prof (__NR_Linux + 44)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_Linux + 45)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_Linux + 46)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_Linux + 47)
+#endif
+
+#if !defined(__NR_signal)
+#define __NR_signal (__NR_Linux + 48)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_Linux + 49)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_Linux + 50)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_Linux + 51)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_Linux + 52)
+#endif
+
+#if !defined(__NR_lock)
+#define __NR_lock (__NR_Linux + 53)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_Linux + 54)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_Linux + 55)
+#endif
+
+#if !defined(__NR_mpx)
+#define __NR_mpx (__NR_Linux + 56)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_Linux + 57)
+#endif
+
+#if !defined(__NR_ulimit)
+#define __NR_ulimit (__NR_Linux + 58)
+#endif
+
+#if !defined(__NR_unused59)
+#define __NR_unused59 (__NR_Linux + 59)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_Linux + 60)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_Linux + 61)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_Linux + 62)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_Linux + 63)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_Linux + 64)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_Linux + 65)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_Linux + 66)
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction (__NR_Linux + 67)
+#endif
+
+#if !defined(__NR_sgetmask)
+#define __NR_sgetmask (__NR_Linux + 68)
+#endif
+
+#if !defined(__NR_ssetmask)
+#define __NR_ssetmask (__NR_Linux + 69)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_Linux + 70)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_Linux + 71)
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend (__NR_Linux + 72)
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending (__NR_Linux + 73)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_Linux + 74)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_Linux + 75)
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit (__NR_Linux + 76)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_Linux + 77)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_Linux + 78)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_Linux + 79)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_Linux + 80)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_Linux + 81)
+#endif
+
+#if !defined(__NR_reserved82)
+#define __NR_reserved82 (__NR_Linux + 82)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_Linux + 83)
+#endif
+
+#if !defined(__NR_unused84)
+#define __NR_unused84 (__NR_Linux + 84)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_Linux + 85)
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib (__NR_Linux + 86)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_Linux + 87)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_Linux + 88)
+#endif
+
+#if !defined(__NR_readdir)
+#define __NR_readdir (__NR_Linux + 89)
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap (__NR_Linux + 90)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_Linux + 91)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_Linux + 92)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_Linux + 93)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_Linux + 94)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_Linux + 95)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_Linux + 96)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_Linux + 97)
+#endif
+
+#if !defined(__NR_profil)
+#define __NR_profil (__NR_Linux + 98)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_Linux + 99)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_Linux + 100)
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm (__NR_Linux + 101)
+#endif
+
+#if !defined(__NR_socketcall)
+#define __NR_socketcall (__NR_Linux + 102)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_Linux + 103)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_Linux + 104)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_Linux + 105)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_Linux + 106)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_Linux + 107)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_Linux + 108)
+#endif
+
+#if !defined(__NR_unused109)
+#define __NR_unused109 (__NR_Linux + 109)
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl (__NR_Linux + 110)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_Linux + 111)
+#endif
+
+#if !defined(__NR_idle)
+#define __NR_idle (__NR_Linux + 112)
+#endif
+
+#if !defined(__NR_vm86)
+#define __NR_vm86 (__NR_Linux + 113)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_Linux + 114)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_Linux + 115)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_Linux + 116)
+#endif
+
+#if !defined(__NR_ipc)
+#define __NR_ipc (__NR_Linux + 117)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_Linux + 118)
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn (__NR_Linux + 119)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_Linux + 120)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_Linux + 121)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_Linux + 122)
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt (__NR_Linux + 123)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_Linux + 124)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_Linux + 125)
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask (__NR_Linux + 126)
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module (__NR_Linux + 127)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_Linux + 128)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_Linux + 129)
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms (__NR_Linux + 130)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_Linux + 131)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_Linux + 132)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_Linux + 133)
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush (__NR_Linux + 134)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_Linux + 135)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_Linux + 136)
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall                               \
+  (__NR_Linux + 137) /* Syscall for Andrew File System \
+                        */
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_Linux + 138)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_Linux + 139)
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek (__NR_Linux + 140)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_Linux + 141)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_Linux + 142)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_Linux + 143)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_Linux + 144)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_Linux + 145)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_Linux + 146)
+#endif
+
+#if !defined(__NR_cacheflush)
+#define __NR_cacheflush (__NR_Linux + 147)
+#endif
+
+#if !defined(__NR_cachectl)
+#define __NR_cachectl (__NR_Linux + 148)
+#endif
+
+#if !defined(__NR_sysmips)
+#define __NR_sysmips (__NR_Linux + 149)
+#endif
+
+#if !defined(__NR_unused150)
+#define __NR_unused150 (__NR_Linux + 150)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_Linux + 151)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_Linux + 152)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_Linux + 153)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_Linux + 154)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_Linux + 155)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_Linux + 156)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_Linux + 157)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_Linux + 158)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_Linux + 159)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_Linux + 160)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_Linux + 161)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_Linux + 162)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_Linux + 163)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_Linux + 164)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_Linux + 165)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_Linux + 166)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_Linux + 167)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_Linux + 168)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_Linux + 169)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_Linux + 170)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_Linux + 171)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_Linux + 172)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_Linux + 173)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_Linux + 174)
+#endif
+
+#if !defined(__NR_recv)
+#define __NR_recv (__NR_Linux + 175)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_Linux + 176)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_Linux + 177)
+#endif
+
+#if !defined(__NR_send)
+#define __NR_send (__NR_Linux + 178)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_Linux + 179)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_Linux + 180)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_Linux + 181)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_Linux + 182)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_Linux + 183)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_Linux + 184)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_Linux + 185)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_Linux + 186)
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module (__NR_Linux + 187)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_Linux + 188)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_Linux + 189)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_Linux + 190)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_Linux + 191)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_Linux + 192)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_Linux + 193)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_Linux + 194)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_Linux + 195)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_Linux + 196)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_Linux + 197)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_Linux + 198)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_Linux + 199)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_Linux + 200)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_Linux + 201)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_Linux + 202)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_Linux + 203)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_Linux + 204)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_Linux + 205)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_Linux + 206)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_Linux + 207)
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg (__NR_Linux + 208)
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg (__NR_Linux + 209)
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 (__NR_Linux + 210)
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 (__NR_Linux + 211)
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 (__NR_Linux + 212)
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 (__NR_Linux + 213)
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 (__NR_Linux + 214)
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 (__NR_Linux + 215)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_Linux + 216)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_Linux + 217)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_Linux + 218)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_Linux + 219)
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 (__NR_Linux + 220)
+#endif
+
+#if !defined(__NR_reserved221)
+#define __NR_reserved221 (__NR_Linux + 221)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_Linux + 222)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_Linux + 223)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_Linux + 224)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_Linux + 225)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_Linux + 226)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_Linux + 227)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_Linux + 228)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_Linux + 229)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_Linux + 230)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_Linux + 231)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_Linux + 232)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_Linux + 233)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_Linux + 234)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_Linux + 235)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_Linux + 236)
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 (__NR_Linux + 237)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_Linux + 238)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_Linux + 239)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_Linux + 240)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_Linux + 241)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_Linux + 242)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_Linux + 243)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_Linux + 244)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_Linux + 245)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_Linux + 246)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_Linux + 247)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_Linux + 248)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_Linux + 249)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_Linux + 250)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_Linux + 251)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_Linux + 252)
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_Linux + 253)
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 (__NR_Linux + 254)
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 (__NR_Linux + 255)
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 (__NR_Linux + 256)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_Linux + 257)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_Linux + 258)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_Linux + 259)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_Linux + 260)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_Linux + 261)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_Linux + 262)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_Linux + 263)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_Linux + 264)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_Linux + 265)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_Linux + 266)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_Linux + 267)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_Linux + 268)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_Linux + 269)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_Linux + 270)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_Linux + 271)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_Linux + 272)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_Linux + 273)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_Linux + 274)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_Linux + 275)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_Linux + 276)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_Linux + 277)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_Linux + 278)
+#endif
+
+/* #define __NR_sys_setaltroot (__NR_Linux + 279) */
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_Linux + 280)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_Linux + 281)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_Linux + 282)
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area (__NR_Linux + 283)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_Linux + 284)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_Linux + 285)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_Linux + 286)
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages (__NR_Linux + 287)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_Linux + 288)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_Linux + 289)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_Linux + 290)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_Linux + 291)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_Linux + 292)
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 (__NR_Linux + 293)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_Linux + 294)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_Linux + 295)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_Linux + 296)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_Linux + 297)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_Linux + 298)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_Linux + 299)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_Linux + 300)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_Linux + 301)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_Linux + 302)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_Linux + 303)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_Linux + 304)
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range (__NR_Linux + 305)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_Linux + 306)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_Linux + 307)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_Linux + 308)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_Linux + 309)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_Linux + 310)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_Linux + 311)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_Linux + 312)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_Linux + 313)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_Linux + 314)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_Linux + 315)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_Linux + 316)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_Linux + 317)
+#endif
+
+#if !defined(__NR_timerfd)
+#define __NR_timerfd (__NR_Linux + 318)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 319)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_Linux + 320)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_Linux + 321)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_Linux + 322)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_Linux + 323)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_Linux + 324)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_Linux + 325)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_Linux + 326)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_Linux + 327)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_Linux + 328)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_Linux + 329)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_Linux + 330)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_Linux + 331)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_Linux + 332)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_Linux + 333)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_Linux + 334)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_Linux + 335)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_Linux + 336)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_Linux + 337)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_Linux + 338)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_Linux + 339)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_Linux + 340)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_Linux + 341)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_Linux + 342)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_Linux + 343)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_Linux + 344)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_Linux + 345)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_Linux + 346)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_Linux + 347)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_Linux + 348)
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr (__NR_Linux + 349)
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr (__NR_Linux + 350)
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 (__NR_Linux + 351)
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp (__NR_Linux + 352)
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_SYSCALLS_H_
diff --git a/libchrome/sandbox/linux/system_headers/mips_linux_ucontext.h b/libchrome/sandbox/linux/system_headers/mips_linux_ucontext.h
new file mode 100644
index 0000000..774bf31
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/mips_linux_ucontext.h
@@ -0,0 +1,53 @@
+// 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 SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
+
+#include <stdint.h>
+
+// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
+// except we do use sigset_t for uc_sigmask instead of a custom type.
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+// Ensure that 'stack_t' is defined.
+#include <asm/signal.h>
+
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef unsigned long greg_t;
+
+typedef struct {
+  uint32_t regmask;
+  uint32_t status;
+  uint64_t pc;
+  uint64_t gregs[32];
+  uint64_t fpregs[32];
+  uint32_t acx;
+  uint32_t fpc_csr;
+  uint32_t fpc_eir;
+  uint32_t used_math;
+  uint32_t dsp;
+  uint64_t mdhi;
+  uint64_t mdlo;
+  uint32_t hi1;
+  uint32_t lo1;
+  uint32_t hi2;
+  uint32_t lo2;
+  uint32_t hi3;
+  uint32_t lo3;
+} mcontext_t;
+
+typedef struct ucontext {
+  uint32_t uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  sigset_t uc_sigmask;
+  // Other fields are not used by Google Breakpad. Don't define them.
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_MIPS_LINUX_UCONTEXT_H_
diff --git a/libchrome/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/libchrome/sandbox/linux/system_headers/x86_32_linux_syscalls.h
new file mode 100644
index 0000000..a6afc62
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/x86_32_linux_syscalls.h
@@ -0,0 +1,1426 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's syscall_32.tbl.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+
+#if !defined(__i386__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 0
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 1
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork 2
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 3
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 4
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open 5
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 6
+#endif
+
+#if !defined(__NR_waitpid)
+#define __NR_waitpid 7
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat 8
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link 9
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink 10
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 11
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 12
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time 13
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod 14
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod 15
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown 16
+#endif
+
+#if !defined(__NR_break)
+#define __NR_break 17
+#endif
+
+#if !defined(__NR_oldstat)
+#define __NR_oldstat 18
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 19
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 20
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 21
+#endif
+
+#if !defined(__NR_umount)
+#define __NR_umount 22
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 23
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 24
+#endif
+
+#if !defined(__NR_stime)
+#define __NR_stime 25
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 26
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm 27
+#endif
+
+#if !defined(__NR_oldfstat)
+#define __NR_oldfstat 28
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause 29
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime 30
+#endif
+
+#if !defined(__NR_stty)
+#define __NR_stty 31
+#endif
+
+#if !defined(__NR_gtty)
+#define __NR_gtty 32
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access 33
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice 34
+#endif
+
+#if !defined(__NR_ftime)
+#define __NR_ftime 35
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 36
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 37
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename 38
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir 39
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir 40
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 41
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe 42
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 43
+#endif
+
+#if !defined(__NR_prof)
+#define __NR_prof 44
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 45
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 46
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 47
+#endif
+
+#if !defined(__NR_signal)
+#define __NR_signal 48
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 49
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 50
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 51
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 52
+#endif
+
+#if !defined(__NR_lock)
+#define __NR_lock 53
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 54
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 55
+#endif
+
+#if !defined(__NR_mpx)
+#define __NR_mpx 56
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 57
+#endif
+
+#if !defined(__NR_ulimit)
+#define __NR_ulimit 58
+#endif
+
+#if !defined(__NR_oldolduname)
+#define __NR_oldolduname 59
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 60
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 61
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat 62
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 63
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 64
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp 65
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 66
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction 67
+#endif
+
+#if !defined(__NR_sgetmask)
+#define __NR_sgetmask 68
+#endif
+
+#if !defined(__NR_ssetmask)
+#define __NR_ssetmask 69
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 70
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 71
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend 72
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending 73
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 74
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 75
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 76
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 77
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 78
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 79
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 80
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 81
+#endif
+
+#if !defined(__NR_select)
+#define __NR_select 82
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink 83
+#endif
+
+#if !defined(__NR_oldlstat)
+#define __NR_oldlstat 84
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink 85
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib 86
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 87
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 88
+#endif
+
+#if !defined(__NR_readdir)
+#define __NR_readdir 89
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 90
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 91
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 92
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 93
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 94
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 95
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 96
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 97
+#endif
+
+#if !defined(__NR_profil)
+#define __NR_profil 98
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 99
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 100
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm 101
+#endif
+
+#if !defined(__NR_socketcall)
+#define __NR_socketcall 102
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 103
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 104
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 105
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat 106
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat 107
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 108
+#endif
+
+#if !defined(__NR_olduname)
+#define __NR_olduname 109
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl 110
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 111
+#endif
+
+#if !defined(__NR_idle)
+#define __NR_idle 112
+#endif
+
+#if !defined(__NR_vm86old)
+#define __NR_vm86old 113
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 114
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 115
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 116
+#endif
+
+#if !defined(__NR_ipc)
+#define __NR_ipc 117
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 118
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn 119
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 120
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 121
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 122
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt 123
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 124
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 125
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask 126
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module 127
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 128
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 129
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms 130
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 131
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 132
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 133
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush 134
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs 135
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 136
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall 137
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 138
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 139
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek 140
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents 141
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect 142
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 143
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 144
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 145
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 146
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 147
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 148
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl 149
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 150
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 151
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 152
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 153
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 154
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 155
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 156
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 157
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 158
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 159
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 160
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 161
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 162
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 163
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 164
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 165
+#endif
+
+#if !defined(__NR_vm86)
+#define __NR_vm86 166
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module 167
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll 168
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 169
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 170
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 171
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 172
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 173
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 174
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 175
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 176
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 177
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 178
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 179
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 180
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 181
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown 182
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 183
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 184
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 185
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 186
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 187
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg 188
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg 189
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork 190
+#endif
+
+#if !defined(__NR_ugetrlimit)
+#define __NR_ugetrlimit 191
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 192
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 193
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 194
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 195
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 196
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 197
+#endif
+
+#if !defined(__NR_lchown32)
+#define __NR_lchown32 198
+#endif
+
+#if !defined(__NR_getuid32)
+#define __NR_getuid32 199
+#endif
+
+#if !defined(__NR_getgid32)
+#define __NR_getgid32 200
+#endif
+
+#if !defined(__NR_geteuid32)
+#define __NR_geteuid32 201
+#endif
+
+#if !defined(__NR_getegid32)
+#define __NR_getegid32 202
+#endif
+
+#if !defined(__NR_setreuid32)
+#define __NR_setreuid32 203
+#endif
+
+#if !defined(__NR_setregid32)
+#define __NR_setregid32 204
+#endif
+
+#if !defined(__NR_getgroups32)
+#define __NR_getgroups32 205
+#endif
+
+#if !defined(__NR_setgroups32)
+#define __NR_setgroups32 206
+#endif
+
+#if !defined(__NR_fchown32)
+#define __NR_fchown32 207
+#endif
+
+#if !defined(__NR_setresuid32)
+#define __NR_setresuid32 208
+#endif
+
+#if !defined(__NR_getresuid32)
+#define __NR_getresuid32 209
+#endif
+
+#if !defined(__NR_setresgid32)
+#define __NR_setresgid32 210
+#endif
+
+#if !defined(__NR_getresgid32)
+#define __NR_getresgid32 211
+#endif
+
+#if !defined(__NR_chown32)
+#define __NR_chown32 212
+#endif
+
+#if !defined(__NR_setuid32)
+#define __NR_setuid32 213
+#endif
+
+#if !defined(__NR_setgid32)
+#define __NR_setgid32 214
+#endif
+
+#if !defined(__NR_setfsuid32)
+#define __NR_setfsuid32 215
+#endif
+
+#if !defined(__NR_setfsgid32)
+#define __NR_setfsgid32 216
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 217
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 218
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 219
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 220
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 221
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 224
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 225
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 226
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 227
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 228
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 229
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 230
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 231
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 232
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 233
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 234
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 235
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 236
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 237
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 238
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 239
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 240
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 241
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 242
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area 243
+#endif
+
+#if !defined(__NR_get_thread_area)
+#define __NR_get_thread_area 244
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 245
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 246
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 247
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 248
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 249
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 250
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 252
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 253
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create 254
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 255
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait 256
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 257
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 258
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 259
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 260
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 261
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 262
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 263
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 264
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 265
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 266
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 267
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 268
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 269
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 270
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes 271
+#endif
+
+#if !defined(__NR_fadvise64_64)
+#define __NR_fadvise64_64 272
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver 273
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 274
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 275
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 276
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 277
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 278
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 279
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 280
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 281
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 282
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 283
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 284
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 286
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 287
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 288
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 289
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 290
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init 291
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 292
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 293
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 294
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 295
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 296
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 297
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 298
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat 299
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 300
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 301
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 302
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 303
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 304
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 305
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 306
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 307
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 308
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 309
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 310
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 311
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 312
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 313
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 314
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 315
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 316
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 317
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 318
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 319
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 320
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd 321
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 322
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd 323
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 324
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 325
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 326
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 327
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 328
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 329
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 330
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 331
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 332
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 333
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 334
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 335
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 336
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 337
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 338
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 339
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 340
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 341
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 342
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 343
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 344
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 345
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 346
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 347
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 348
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 349
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 350
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 351
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 352
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 353
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 354
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 355
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create 356
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+
diff --git a/libchrome/sandbox/linux/system_headers/x86_64_linux_syscalls.h b/libchrome/sandbox/linux/system_headers/x86_64_linux_syscalls.h
new file mode 100644
index 0000000..349504a
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/x86_64_linux_syscalls.h
@@ -0,0 +1,1294 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Generated from the Linux kernel's syscall_64.tbl.
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+
+#if !defined(__x86_64__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 0
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 1
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open 2
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 3
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat 4
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 5
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat 6
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll 7
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 8
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 9
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 10
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 11
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 12
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 13
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 14
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 15
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 16
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 17
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 18
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 19
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 20
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access 21
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe 22
+#endif
+
+#if !defined(__NR_select)
+#define __NR_select 23
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 24
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 25
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 26
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 27
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 28
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 29
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 30
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 31
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 32
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 33
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause 34
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 35
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 36
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm 37
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 38
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 39
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 40
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 41
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 42
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept 43
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 44
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 45
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 46
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 47
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 48
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 49
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 50
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 51
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 52
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 53
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 54
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 55
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 56
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork 57
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork 58
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 59
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 60
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 61
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 62
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 63
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 64
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop 65
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 66
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 67
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 68
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 69
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 70
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 71
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 72
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 73
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 74
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 75
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 76
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 77
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents 78
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 79
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 80
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 81
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename 82
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir 83
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir 84
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat 85
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link 86
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink 87
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink 88
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink 89
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod 90
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 91
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown 92
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 93
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown 94
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 95
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 96
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 97
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 98
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 99
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 100
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 101
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 102
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 103
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 104
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 105
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 106
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 107
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 108
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 109
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 110
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp 111
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 112
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 113
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 114
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 115
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 116
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 117
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 118
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 119
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 120
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 121
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 122
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 123
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 124
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 125
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 126
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 127
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 128
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 129
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 130
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 131
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime 132
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod 133
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib 134
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 135
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat 136
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 137
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 138
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs 139
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 140
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 141
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 142
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 143
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 144
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 145
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 146
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 147
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 148
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 149
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 150
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 151
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 152
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 153
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt 154
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 155
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl 156
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 157
+#endif
+
+#if !defined(__NR_arch_prctl)
+#define __NR_arch_prctl 158
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 159
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 160
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 161
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 162
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 163
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 164
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 165
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 166
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 167
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 168
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 169
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 170
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 171
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl 172
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm 173
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module 174
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 175
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 176
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms 177
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module 178
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 179
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 180
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg 181
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg 182
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall 183
+#endif
+
+#if !defined(__NR_tuxcall)
+#define __NR_tuxcall 184
+#endif
+
+#if !defined(__NR_security)
+#define __NR_security 185
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 186
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 187
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 188
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 189
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 190
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 191
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 192
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 193
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 194
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 195
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 196
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 197
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 198
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 199
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 200
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time 201
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 202
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 203
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 204
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area 205
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 206
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 207
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 208
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 209
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 210
+#endif
+
+#if !defined(__NR_get_thread_area)
+#define __NR_get_thread_area 211
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 212
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create 213
+#endif
+
+#if !defined(__NR_epoll_ctl_old)
+#define __NR_epoll_ctl_old 214
+#endif
+
+#if !defined(__NR_epoll_wait_old)
+#define __NR_epoll_wait_old 215
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 216
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 217
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 218
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 219
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop 220
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 221
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 222
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 223
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 224
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 225
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 226
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 227
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 228
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 229
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 230
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 231
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait 232
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 233
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 234
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes 235
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver 236
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 237
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 238
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 239
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 240
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 241
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 242
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 243
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 244
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 245
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 246
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 247
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 248
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 249
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 250
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 251
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 252
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init 253
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 254
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 255
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 256
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 257
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 258
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 259
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 260
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat 261
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat 262
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 263
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 264
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 265
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 266
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 267
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 268
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 269
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 270
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 271
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 272
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 273
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 274
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 275
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 276
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 277
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 278
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 279
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 280
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 281
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd 282
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 283
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd 284
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 285
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 286
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 287
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 288
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 289
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 290
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 291
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 292
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 293
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 294
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 295
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 296
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 297
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 298
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 299
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 300
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 301
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 302
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 303
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 304
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 305
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 306
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 307
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 308
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 309
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 310
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 311
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 312
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 313
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 314
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 315
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 316
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 317
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 318
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create 319
+#endif
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+
diff --git a/libchrome/sandbox/linux/system_headers/x86_64_linux_ucontext.h b/libchrome/sandbox/linux/system_headers/x86_64_linux_ucontext.h
new file mode 100644
index 0000000..1f1abe6
--- /dev/null
+++ b/libchrome/sandbox/linux/system_headers/x86_64_linux_ucontext.h
@@ -0,0 +1,90 @@
+// 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 SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
+
+#include <stdint.h>
+
+// We do something compatible with glibc. Hopefully, at some point Android will
+// provide that for us, and __BIONIC_HAVE_UCONTEXT_T should be defined.
+// Spec:
+// http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-AMD64/LSB-Core-AMD64/libc-ddefs.html#AEN5668
+
+#if !defined(__BIONIC_HAVE_UCONTEXT_T)
+#include <asm/sigcontext.h>
+
+struct _libc_fpxreg {
+  unsigned short significand[4];
+  unsigned short exponent;
+  unsigned short padding[3];
+};
+
+struct _libc_xmmreg {
+  uint32_t element[4];
+};
+
+struct _libc_fpstate {
+  uint16_t cwd;
+  uint16_t swd;
+  uint16_t twd;
+  uint16_t fop;
+  uint64_t rip;
+  uint64_t rdp;
+  uint32_t mxcsr;
+  uint32_t mxcsr_mask;
+  struct _libc_fpxreg _st[8];
+  struct _libc_xmmreg _xmm[16];
+  uint32_t padding[24];
+};
+
+typedef uint64_t greg_t;
+
+typedef struct {
+  greg_t gregs[23];
+  struct _libc_fpstate* fpregs;
+  unsigned long __reserved1[8];
+} mcontext_t;
+
+enum {
+  REG_R8 = 0,
+  REG_R9,
+  REG_R10,
+  REG_R11,
+  REG_R12,
+  REG_R13,
+  REG_R14,
+  REG_R15,
+  REG_RDI,
+  REG_RSI,
+  REG_RBP,
+  REG_RBX,
+  REG_RDX,
+  REG_RAX,
+  REG_RCX,
+  REG_RSP,
+  REG_RIP,
+  REG_EFL,
+  REG_CSGSFS,
+  REG_ERR,
+  REG_TRAPNO,
+  REG_OLDMASK,
+  REG_CR2,
+  NGREG,
+};
+
+typedef struct ucontext {
+  unsigned long uc_flags;
+  struct ucontext* uc_link;
+  stack_t uc_stack;
+  mcontext_t uc_mcontext;
+  sigset_t uc_sigmask;
+  struct _libc_fpstate __fpregs_mem;
+} ucontext_t;
+
+#else
+#include <sys/ucontext.h>
+#endif  // __BIONIC_HAVE_UCONTEXT_T
+
+#endif  // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_UCONTEXT_H_
diff --git a/libchrome/sandbox/mac/BUILD.gn b/libchrome/sandbox/mac/BUILD.gn
new file mode 100644
index 0000000..fd53131
--- /dev/null
+++ b/libchrome/sandbox/mac/BUILD.gn
@@ -0,0 +1,64 @@
+# 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/mac/mac_sdk.gni")
+import("//testing/test.gni")
+
+component("sandbox") {
+  sources = [
+    "bootstrap_sandbox.cc",
+    "bootstrap_sandbox.h",
+    "launchd_interception_server.cc",
+    "launchd_interception_server.h",
+    "mach_message_server.cc",
+    "mach_message_server.h",
+    "message_server.h",
+    "os_compatibility.cc",
+    "os_compatibility.h",
+    "policy.cc",
+    "policy.h",
+    "pre_exec_delegate.cc",
+    "pre_exec_delegate.h",
+    "xpc.h",
+    "xpc_message_server.cc",
+    "xpc_message_server.h",
+  ]
+
+  defines = [ "SANDBOX_IMPLEMENTATION" ]
+  libs = [ "bsm" ]
+
+  deps = [
+    "//base",
+  ]
+}
+
+component("seatbelt") {
+  sources = [
+    "seatbelt.cc",
+    "seatbelt.h",
+    "seatbelt_export.h",
+  ]
+  libs = [ "sandbox" ]
+  defines = [ "SEATBELT_IMPLEMENTATION" ]
+}
+
+test("sandbox_mac_unittests") {
+  sources = [
+    "bootstrap_sandbox_unittest.mm",
+    "policy_unittest.cc",
+    "xpc_message_server_unittest.cc",
+  ]
+
+  libs = [
+    "CoreFoundation.framework",
+    "Foundation.framework",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//testing/gtest",
+  ]
+}
diff --git a/libchrome/sandbox/mac/OWNERS b/libchrome/sandbox/mac/OWNERS
new file mode 100644
index 0000000..163563f
--- /dev/null
+++ b/libchrome/sandbox/mac/OWNERS
@@ -0,0 +1,2 @@
+mark@chromium.org
+rsesek@chromium.org
diff --git a/libchrome/sandbox/mac/message_server.h b/libchrome/sandbox/mac/message_server.h
new file mode 100644
index 0000000..6ee119b
--- /dev/null
+++ b/libchrome/sandbox/mac/message_server.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 SANDBOX_MAC_MESSAGE_SERVER_H_
+#define SANDBOX_MAC_MESSAGE_SERVER_H_
+
+#include <mach/mach.h>
+#include <unistd.h>
+
+#include "sandbox/mac/xpc.h"
+
+namespace sandbox {
+
+// A message received by a MessageServer. Each concrete implementation of
+// that interface will handle the fields of this union appropriately.
+// Consumers should treat this as an opaque handle.
+union IPCMessage {
+  mach_msg_header_t* mach;
+  xpc_object_t xpc;
+};
+
+// A delegate interface for MessageServer that handles processing of
+// incoming intercepted IPC messages.
+class MessageDemuxer {
+ public:
+  // Handle a |request| message. The message is owned by the server. Use the
+  // server's methods to create and send a reply message.
+  virtual void DemuxMessage(IPCMessage request) = 0;
+
+ protected:
+  virtual ~MessageDemuxer() {}
+};
+
+// An interaface for an IPC server that implements Mach messaging semantics.
+// The concrete implementation may be powered by raw Mach messages, XPC, or
+// some other technology. This interface is the abstraction on top of those
+// that enables message interception.
+class MessageServer {
+ public:
+  virtual ~MessageServer() {}
+
+  // Initializes the class and starts running the message server. If this
+  // returns false, no other methods may be called on this class.
+  virtual bool Initialize() = 0;
+
+  // Blocks the calling thread while the server shuts down. This prevents
+  // the server from receiving new messages. After this method is called,
+  // no other methods may be called on this class.
+  virtual void Shutdown() = 0;
+
+  // Given a received request message, returns the PID of the sending process.
+  virtual pid_t GetMessageSenderPID(IPCMessage request) = 0;
+
+  // Creates a reply message from a request message. The result is owned by
+  // the server.
+  virtual IPCMessage CreateReply(IPCMessage request) = 0;
+
+  // Sends a reply message. Returns true if the message was sent successfully.
+  virtual bool SendReply(IPCMessage reply) = 0;
+
+  // Forwards the original |request| to the |destination| for handling.
+  virtual void ForwardMessage(IPCMessage request, mach_port_t destination) = 0;
+
+  // Replies to the received |request| message by creating a reply and setting
+  // the specified |error_code| in a field that is interpreted by the
+  // underlying IPC system.
+  virtual void RejectMessage(IPCMessage request, int error_code) = 0;
+
+  // Returns the Mach port on which the MessageServer is listening.
+  virtual mach_port_t GetServerPort() const = 0;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_MAC_MESSAGE_SERVER_H_
diff --git a/libchrome/sandbox/mac/sandbox_mac.gypi b/libchrome/sandbox/mac/sandbox_mac.gypi
new file mode 100644
index 0000000..79740e5
--- /dev/null
+++ b/libchrome/sandbox/mac/sandbox_mac.gypi
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'seatbelt',
+      'type' : '<(component)',
+      'sources': [
+        'seatbelt.cc',
+        'seatbelt.h',
+        'seatbelt_export.h',
+      ],
+      'defines': [
+        'SEATBELT_IMPLEMENTATION',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/usr/lib/libsandbox.dylib',
+        ],
+      }
+    },
+    {
+      'target_name': 'sandbox',
+      'type': '<(component)',
+      'sources': [
+        'bootstrap_sandbox.cc',
+        'bootstrap_sandbox.h',
+        'launchd_interception_server.cc',
+        'launchd_interception_server.h',
+        'mach_message_server.cc',
+        'mach_message_server.h',
+        'message_server.h',
+        'os_compatibility.cc',
+        'os_compatibility.h',
+        'policy.cc',
+        'policy.h',
+        'pre_exec_delegate.cc',
+        'pre_exec_delegate.h',
+        'xpc.h',
+        'xpc_message_server.cc',
+        'xpc_message_server.h',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+      ],
+      'include_dirs': [
+        '..',
+        '<(SHARED_INTERMEDIATE_DIR)',
+      ],
+      'defines': [
+        'SANDBOX_IMPLEMENTATION',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/usr/lib/libbsm.dylib',
+        ],
+      },
+    },
+    {
+      'target_name': 'sandbox_mac_unittests',
+      'type': 'executable',
+      'sources': [
+        'bootstrap_sandbox_unittest.mm',
+        'policy_unittest.cc',
+        'xpc_message_server_unittest.cc',
+      ],
+      'dependencies': [
+        'sandbox',
+        '../base/base.gyp:base',
+        '../base/base.gyp:run_all_unittests',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+        ],
+      },
+    },
+  ],
+  'conditions': [
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'sandbox_mac_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'sandbox_mac_unittests',
+          ],
+          'includes': [ '../../build/isolate.gypi' ],
+          'sources': [ '../sandbox_mac_unittests.isolate' ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/sandbox/sandbox.gyp b/libchrome/sandbox/sandbox.gyp
new file mode 100644
index 0000000..f93fa18
--- /dev/null
+++ b/libchrome/sandbox/sandbox.gyp
@@ -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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'conditions': [
+    [ 'OS=="win"', {
+      'includes': [
+        'win/sandbox_win.gypi',
+      ],
+    }],
+    [ 'OS=="linux" or OS=="android"', {
+      'includes': [
+        'linux/sandbox_linux.gypi',
+      ],
+    }],
+    [ 'OS=="mac" and OS!="ios"', {
+      'includes': [
+        'mac/sandbox_mac.gypi',
+      ],
+    }],
+    [ 'OS!="win" and OS!="mac" and OS!="linux" and OS!="android"', {
+      # A 'default' to accomodate the "sandbox" target.
+      'targets': [
+        {
+          'target_name': 'sandbox',
+          'type': 'none',
+        }
+       ]
+    }],
+  ],
+}
diff --git a/libchrome/sandbox/sandbox_export.h b/libchrome/sandbox/sandbox_export.h
new file mode 100644
index 0000000..35d6a1b
--- /dev/null
+++ b/libchrome/sandbox/sandbox_export.h
@@ -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.
+
+#ifndef SANDBOX_SANDBOX_EXPORT_H_
+#define SANDBOX_SANDBOX_EXPORT_H_
+
+#if defined(WIN32)
+#error "sandbox_export.h does not support WIN32."
+#endif
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(SANDBOX_IMPLEMENTATION)
+#define SANDBOX_EXPORT __attribute__((visibility("default")))
+#else
+#define SANDBOX_EXPORT
+#endif  // defined(SANDBOX_IMPLEMENTATION)
+
+#else  // defined(COMPONENT_BUILD)
+
+#define SANDBOX_EXPORT
+
+#endif  // defined(COMPONENT_BUILD)
+
+#endif  // SANDBOX_SANDBOX_EXPORT_H_
diff --git a/libchrome/sandbox/sandbox_linux_unittests.isolate b/libchrome/sandbox/sandbox_linux_unittests.isolate
new file mode 100644
index 0000000..2b7c2a7
--- /dev/null
+++ b/libchrome/sandbox/sandbox_linux_unittests.isolate
@@ -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.
+
+# Because of a limitation in isolate_driver.py, this file needs to be in
+# the same directory as the main .gyp file.
+
+{
+  'conditions': [
+    ['OS=="android" or OS=="linux"', {
+      'variables': {
+        'command': [
+          '<(PRODUCT_DIR)/sandbox_linux_unittests',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    # This is needed because of base/ dependencies on
+    # icudtl.dat.
+    '../base/base.isolate',
+  ],
+}
diff --git a/libchrome/sandbox/win/BUILD.gn b/libchrome/sandbox/win/BUILD.gn
new file mode 100644
index 0000000..60bb499
--- /dev/null
+++ b/libchrome/sandbox/win/BUILD.gn
@@ -0,0 +1,326 @@
+# 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("//testing/test.gni")
+
+# This needs to be a static library rather than a sources set because small
+# portions of this are used in some contexts (like chrome_elf), and it
+# doesnn't seem to dead-code strip very well. This saves 12K on chrome_elf.dll,
+# over a source set, for example.
+static_library("sandbox") {
+  sources = [
+    "src/acl.cc",
+    "src/acl.h",
+    "src/broker_services.cc",
+    "src/broker_services.h",
+    "src/crosscall_client.h",
+    "src/crosscall_params.h",
+    "src/crosscall_server.cc",
+    "src/crosscall_server.h",
+    "src/eat_resolver.cc",
+    "src/eat_resolver.h",
+    "src/filesystem_dispatcher.cc",
+    "src/filesystem_dispatcher.h",
+    "src/filesystem_interception.cc",
+    "src/filesystem_interception.h",
+    "src/filesystem_policy.cc",
+    "src/filesystem_policy.h",
+    "src/handle_closer.cc",
+    "src/handle_closer.h",
+    "src/handle_closer_agent.cc",
+    "src/handle_closer_agent.h",
+    "src/interception.cc",
+    "src/interception.h",
+    "src/interception_agent.cc",
+    "src/interception_agent.h",
+    "src/interception_internal.h",
+    "src/interceptors.h",
+    "src/internal_types.h",
+    "src/ipc_tags.h",
+    "src/job.cc",
+    "src/job.h",
+    "src/named_pipe_dispatcher.cc",
+    "src/named_pipe_dispatcher.h",
+    "src/named_pipe_interception.cc",
+    "src/named_pipe_interception.h",
+    "src/named_pipe_policy.cc",
+    "src/named_pipe_policy.h",
+    "src/nt_internals.h",
+    "src/policy_broker.cc",
+    "src/policy_broker.h",
+    "src/policy_engine_opcodes.cc",
+    "src/policy_engine_opcodes.h",
+    "src/policy_engine_params.h",
+    "src/policy_engine_processor.cc",
+    "src/policy_engine_processor.h",
+    "src/policy_low_level.cc",
+    "src/policy_low_level.h",
+    "src/policy_params.h",
+    "src/policy_target.cc",
+    "src/policy_target.h",
+    "src/process_mitigations.cc",
+    "src/process_mitigations.h",
+    "src/process_mitigations_win32k_dispatcher.cc",
+    "src/process_mitigations_win32k_dispatcher.h",
+    "src/process_mitigations_win32k_interception.cc",
+    "src/process_mitigations_win32k_interception.h",
+    "src/process_mitigations_win32k_policy.cc",
+    "src/process_mitigations_win32k_policy.h",
+    "src/process_thread_dispatcher.cc",
+    "src/process_thread_dispatcher.h",
+    "src/process_thread_interception.cc",
+    "src/process_thread_interception.h",
+    "src/process_thread_policy.cc",
+    "src/process_thread_policy.h",
+    "src/registry_dispatcher.cc",
+    "src/registry_dispatcher.h",
+    "src/registry_interception.cc",
+    "src/registry_interception.h",
+    "src/registry_policy.cc",
+    "src/registry_policy.h",
+    "src/resolver.cc",
+    "src/resolver.h",
+    "src/restricted_token.cc",
+    "src/restricted_token.h",
+    "src/restricted_token_utils.cc",
+    "src/restricted_token_utils.h",
+    "src/sandbox.cc",
+    "src/sandbox.h",
+    "src/sandbox_factory.h",
+    "src/sandbox_globals.cc",
+    "src/sandbox_nt_types.h",
+    "src/sandbox_nt_util.cc",
+    "src/sandbox_nt_util.h",
+    "src/sandbox_policy.h",
+    "src/sandbox_policy_base.cc",
+    "src/sandbox_policy_base.h",
+    "src/sandbox_rand.cc",
+    "src/sandbox_rand.h",
+    "src/sandbox_types.h",
+    "src/sandbox_utils.cc",
+    "src/sandbox_utils.h",
+    "src/security_level.h",
+    "src/service_resolver.cc",
+    "src/service_resolver.h",
+    "src/sharedmem_ipc_client.cc",
+    "src/sharedmem_ipc_client.h",
+    "src/sharedmem_ipc_server.cc",
+    "src/sharedmem_ipc_server.h",
+    "src/sid.cc",
+    "src/sid.h",
+    "src/sync_dispatcher.cc",
+    "src/sync_dispatcher.h",
+    "src/sync_interception.cc",
+    "src/sync_interception.h",
+    "src/sync_policy.cc",
+    "src/sync_policy.h",
+    "src/target_interceptions.cc",
+    "src/target_interceptions.h",
+    "src/target_process.cc",
+    "src/target_process.h",
+    "src/target_services.cc",
+    "src/target_services.h",
+    "src/top_level_dispatcher.cc",
+    "src/top_level_dispatcher.h",
+    "src/win2k_threadpool.cc",
+    "src/win2k_threadpool.h",
+    "src/win_utils.cc",
+    "src/win_utils.h",
+    "src/window.cc",
+    "src/window.h",
+  ]
+
+  if (current_cpu == "x64") {
+    sources += [
+      "src/interceptors_64.cc",
+      "src/interceptors_64.h",
+      "src/resolver_64.cc",
+      "src/service_resolver_64.cc",
+    ]
+  } else if (current_cpu == "x86") {
+    sources += [
+      "src/resolver_32.cc",
+      "src/service_resolver_32.cc",
+      "src/sidestep/ia32_modrm_map.cpp",
+      "src/sidestep/ia32_opcode_map.cpp",
+      "src/sidestep/mini_disassembler.cpp",
+      "src/sidestep/mini_disassembler.h",
+      "src/sidestep/mini_disassembler_types.h",
+      "src/sidestep/preamble_patcher.h",
+      "src/sidestep/preamble_patcher_with_stub.cpp",
+      "src/sidestep_resolver.cc",
+      "src/sidestep_resolver.h",
+    ]
+  }
+
+  configs += [ "//build/config:precompiled_headers" ]
+
+  deps = [
+    "//base",
+    "//base:base_static",
+  ]
+  if (current_cpu == "x86") {
+    deps += [ ":copy_wow_helper" ]
+  }
+}
+
+if (current_cpu == "x86") {
+  # Make a target that copies the wow_helper files to the out dir.
+  #
+  # TODO(brettw) we can probably just build this now that we have proper
+  # toolchain support.
+  copy("copy_wow_helper") {
+    sources = [
+      "wow_helper/wow_helper.exe",
+      "wow_helper/wow_helper.pdb",
+    ]
+    outputs = [
+      "$root_out_dir/{{source_file_part}}",
+    ]
+  }
+}
+
+test("sbox_integration_tests") {
+  sources = [
+    "src/address_sanitizer_test.cc",
+    "src/app_container_test.cc",
+    "src/file_policy_test.cc",
+    "src/handle_closer_test.cc",
+    "src/handle_inheritance_test.cc",
+    "src/integrity_level_test.cc",
+    "src/ipc_ping_test.cc",
+    "src/lpc_policy_test.cc",
+    "src/named_pipe_policy_test.cc",
+    "src/policy_target_test.cc",
+    "src/process_mitigations_test.cc",
+    "src/process_policy_test.cc",
+    "src/registry_policy_test.cc",
+    "src/restricted_token_test.cc",
+    "src/sync_policy_test.cc",
+    "src/sync_policy_test.h",
+    "src/unload_dll_test.cc",
+    "tests/common/controller.cc",
+    "tests/common/controller.h",
+    "tests/common/test_utils.cc",
+    "tests/common/test_utils.h",
+    "tests/integration_tests/integration_tests.cc",
+    "tests/integration_tests/integration_tests_common.h",
+    "tests/integration_tests/integration_tests_test.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    ":sbox_integration_test_hook_dll",
+    ":sbox_integration_test_win_proc",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+
+  libs = [ "dxva2.lib" ]
+}
+
+loadable_module("sbox_integration_test_hook_dll") {
+  sources = [
+    "tests/integration_tests/hooking_dll.cc",
+    "tests/integration_tests/integration_tests_common.h",
+  ]
+}
+
+executable("sbox_integration_test_win_proc") {
+  sources = [
+    "tests/integration_tests/hooking_win_proc.cc",
+    "tests/integration_tests/integration_tests_common.h",
+  ]
+
+  configs -= [ "//build/config/win:console" ]
+  configs += [ "//build/config/win:windowed" ]
+}
+
+test("sbox_validation_tests") {
+  sources = [
+    "tests/common/controller.cc",
+    "tests/common/controller.h",
+    "tests/validation_tests/commands.cc",
+    "tests/validation_tests/commands.h",
+    "tests/validation_tests/suite.cc",
+    "tests/validation_tests/unit_tests.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+
+  libs = [ "shlwapi.lib" ]
+}
+
+test("sbox_unittests") {
+  sources = [
+    "src/interception_unittest.cc",
+    "src/ipc_unittest.cc",
+    "src/job_unittest.cc",
+    "src/policy_engine_unittest.cc",
+    "src/policy_low_level_unittest.cc",
+    "src/policy_opcodes_unittest.cc",
+    "src/restricted_token_unittest.cc",
+    "src/sandbox_nt_util_unittest.cc",
+    "src/service_resolver_unittest.cc",
+    "src/sid_unittest.cc",
+    "src/threadpool_unittest.cc",
+    "src/win_utils_unittest.cc",
+    "tests/common/test_utils.cc",
+    "tests/common/test_utils.h",
+    "tests/unit_tests/unit_tests.cc",
+  ]
+
+  deps = [
+    ":sandbox",
+    "//base/test:test_support",
+    "//testing/gtest",
+  ]
+}
+
+test("sandbox_poc") {
+  sources = [
+    "sandbox_poc/main_ui_window.cc",
+    "sandbox_poc/main_ui_window.h",
+    "sandbox_poc/resource.h",
+    "sandbox_poc/sandbox.cc",
+    "sandbox_poc/sandbox.h",
+    "sandbox_poc/sandbox.ico",
+    "sandbox_poc/sandbox.rc",
+  ]
+
+  configs -= [ "//build/config/win:console" ]
+  configs += [ "//build/config/win:windowed" ]
+
+  libs = [ "comctl32.lib" ]
+
+  deps = [
+    ":pocdll",
+    ":sandbox",
+  ]
+}
+
+shared_library("pocdll") {
+  sources = [
+    "sandbox_poc/pocdll/exports.h",
+    "sandbox_poc/pocdll/fs.cc",
+    "sandbox_poc/pocdll/handles.cc",
+    "sandbox_poc/pocdll/invasive.cc",
+    "sandbox_poc/pocdll/network.cc",
+    "sandbox_poc/pocdll/pocdll.cc",
+    "sandbox_poc/pocdll/processes_and_threads.cc",
+    "sandbox_poc/pocdll/registry.cc",
+    "sandbox_poc/pocdll/spyware.cc",
+    "sandbox_poc/pocdll/utils.h",
+  ]
+
+  defines = [ "POCDLL_EXPORTS" ]
+
+  deps = [
+    "//build/config/sanitizers:deps",
+  ]
+}
diff --git a/libchrome/sandbox/win/OWNERS b/libchrome/sandbox/win/OWNERS
new file mode 100644
index 0000000..54a76c1
--- /dev/null
+++ b/libchrome/sandbox/win/OWNERS
@@ -0,0 +1,4 @@
+cpu@chromium.org
+forshaw@chromium.org
+jschuh@chromium.org
+wfh@chromium.org
diff --git a/libchrome/sandbox/win/sandbox_poc/pocdll/exports.h b/libchrome/sandbox/win/sandbox_poc/pocdll/exports.h
new file mode 100644
index 0000000..66a07d6
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_poc/pocdll/exports.h
@@ -0,0 +1,89 @@
+// 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 SANDBOX_SANDBOX_POC_POCDLL_EXPORTS_H__
+#define SANDBOX_SANDBOX_POC_POCDLL_EXPORTS_H__
+
+#include <windows.h>
+
+#ifdef POCDLL_EXPORTS
+#define POCDLL_API __declspec(dllexport) __cdecl
+#else
+#define POCDLL_API __declspec(dllimport) __cdecl
+#endif
+
+extern "C" {
+// Tries to open several known system path and outputs
+// the result.
+// "log" is the handle of the log file.
+void POCDLL_API TestFileSystem(HANDLE log);
+
+// Tries to find all handles open in the process and prints the name of the
+// resource references by the handle along with the access right.
+// "log" is the handle of the log file.
+void POCDLL_API TestGetHandle(HANDLE log);
+
+// Creates a lot of threads until it cannot create more. The goal of this
+// function is to determine if it's possible to crash the machine when we
+// flood the machine with new threads
+// "log" is the handle of the log file.
+void POCDLL_API TestThreadBombing(HANDLE log);
+
+// Takes all cpu of the machine. For each processor on the machine we assign
+// a thread. This thread will compute a mathematical expression over and over
+// to take all cpu.
+// "log" is the handle of the log file.
+// Note: here we are using the affinity to find out how many processors are on
+// the machine and to force a thread to run only on a given processor.
+void POCDLL_API TestTakeAllCpu(HANDLE log);
+
+// Creates memory in the heap until it fails 5 times in a row and prints the
+// amount of memory created. This function is used to find out if it's possible
+// to take all memory on the machine and crash the system.
+// "log" is the handle of the log file.
+void POCDLL_API TestUseAllMemory(HANDLE log);
+
+// Creates millions of kernel objects. This function is used to find out if it's
+// possible to crash the system if we create too many kernel objects and if we
+// hold too many handles. All those kernel objects are unnamed.
+// "log" is the handle of the log file.
+void POCDLL_API TestCreateObjects(HANDLE log);
+
+// Receives a hwnd and tries to close it. This is the callback for EnumWindows.
+// It will be called for each window(hwnd) on the system.
+// "log" is the handle of the log file.
+// Always returns TRUE to tell the system that we want to continue the
+// enumeration.
+void POCDLL_API TestCloseHWND(HANDLE log);
+
+// Tries to listen on the port 88.
+// "log" is the handle of the log file.
+void POCDLL_API TestNetworkListen(HANDLE log);
+
+// Lists all processes on the system and tries to open them
+// "log" is the handle of the log file.
+void POCDLL_API TestProcesses(HANDLE log);
+
+// Lists all threads on the system and tries to open them
+// "log" is the handle of the log file.
+void POCDLL_API TestThreads(HANDLE log);
+
+// Tries to open some known system registry key and outputs the result.
+// "log" is the handle of the log file.
+void POCDLL_API TestRegistry(HANDLE log);
+
+// Records all keystrokes typed for 15 seconds and then display them.
+// "log" is the handle of the log file.
+void POCDLL_API TestSpyKeys(HANDLE log);
+
+// Tries to read pixels on the monitor and output if the operation
+// failes or succeeded.
+// "log" is the handle of the log file.
+void POCDLL_API TestSpyScreen(HANDLE log);
+
+// Runs all tests except those who are invasive
+void POCDLL_API Run(HANDLE log);
+}
+
+#endif  // SANDBOX_SANDBOX_POC_POCDLL_EXPORTS_H__
diff --git a/libchrome/sandbox/win/sandbox_poc/pocdll/pocdll.vcproj b/libchrome/sandbox/win/sandbox_poc/pocdll/pocdll.vcproj
new file mode 100644
index 0000000..8e4e31f
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_poc/pocdll/pocdll.vcproj
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="pocdll"
+	ProjectGUID="{AE5BFB87-850E-4454-B01D-58E7D8BAC224}"
+	RootNamespace="pocdll"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="POCDLL_EXPORTS"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				ModuleDefinitionFile=""
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+				EmbedManifest="false"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="POCDLL_EXPORTS"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				ModuleDefinitionFile=""
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+				EmbedManifest="false"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\exports.h"
+			>
+		</File>
+		<File
+			RelativePath=".\fs.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\handles.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\invasive.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\network.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\pocdll.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\processes_and_threads.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\registry.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\spyware.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+		<File
+			RelativePath=".\utils.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/sandbox_poc/pocdll/utils.h b/libchrome/sandbox/win/sandbox_poc/pocdll/utils.h
new file mode 100644
index 0000000..0a6ad37
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_poc/pocdll/utils.h
@@ -0,0 +1,66 @@
+// 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 SANDBOX_SANDBOX_POC_POCDLL_UTILS_H__
+#define SANDBOX_SANDBOX_POC_POCDLL_UTILS_H__
+
+#include <stdio.h>
+#include <io.h>
+
+#include "base/macros.h"
+
+// Class to convert a HANDLE to a FILE *. The FILE * is closed when the
+// object goes out of scope
+class HandleToFile {
+ public:
+  HandleToFile() {
+    file_ = NULL;
+  };
+
+  // Note: c_file_handle_ does not need to be closed because fclose does it.
+  ~HandleToFile() {
+    if (file_) {
+      fflush(file_);
+      fclose(file_);
+    }
+  };
+
+  // Translates a HANDLE (handle) to a FILE * opened with the mode "mode".
+  // The return value is the FILE * or NULL if there is an error.
+  FILE* Translate(HANDLE handle, const char *mode) {
+    if (file_) {
+      return  NULL;
+    }
+
+    HANDLE new_handle;
+    BOOL result = ::DuplicateHandle(::GetCurrentProcess(),
+                                    handle,
+                                    ::GetCurrentProcess(),
+                                    &new_handle,
+                                    0,  // Don't ask for a specific
+                                        // desired access.
+                                    FALSE,  // Not inheritable.
+                                    DUPLICATE_SAME_ACCESS);
+
+    if (!result) {
+      return NULL;
+    }
+
+    int c_file_handle = _open_osfhandle(reinterpret_cast<LONG_PTR>(new_handle),
+                                        0);  // No flags
+    if (-1 == c_file_handle) {
+      return NULL;
+    }
+
+    file_ = _fdopen(c_file_handle, mode);
+    return file_;
+  };
+ private:
+  // the FILE* returned. We need to closed it at the end.
+  FILE* file_;
+
+  DISALLOW_COPY_AND_ASSIGN(HandleToFile);
+};
+
+#endif  // SANDBOX_SANDBOX_POC_POCDLL_UTILS_H__
diff --git a/libchrome/sandbox/win/sandbox_poc/resource.h b/libchrome/sandbox/win/sandbox_poc/resource.h
new file mode 100644
index 0000000..87ff920
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_poc/resource.h
@@ -0,0 +1,30 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by sandbox.rc
+//
+#define IDI_SANDBOX                     107
+#define IDR_MENU_MAIN_UI                129
+#define IDD_LAUNCH_DLL                  130
+#define IDC_RADIO_POCDLL                1000
+#define IDC_RADIO_CUSTOM_DLL            1001
+#define IDC_DLL_NAME                    1002
+#define IDC_ENTRY_POINT                 1003
+#define IDC_LOG_FILE                    1004
+#define IDC_BROWSE_DLL                  1005
+#define IDC_BROWSE_LOG                  1006
+#define ID_FILE_EXIT                    32771
+#define ID_COMMANDS_LAUNCHDLL           32772
+#define ID_COMMANDS_SPAWNTARGET         32773
+#define IDC_STATIC                      -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC                     1
+#define _APS_NEXT_RESOURCE_VALUE        131
+#define _APS_NEXT_COMMAND_VALUE         32774
+#define _APS_NEXT_CONTROL_VALUE         1007
+#define _APS_NEXT_SYMED_VALUE           110
+#endif
+#endif
diff --git a/libchrome/sandbox/win/sandbox_poc/sandbox.ico b/libchrome/sandbox/win/sandbox_poc/sandbox.ico
new file mode 100644
index 0000000..916fa12
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_poc/sandbox.ico
Binary files differ
diff --git a/libchrome/sandbox/win/sandbox_poc/sandbox.rc b/libchrome/sandbox/win/sandbox_poc/sandbox.rc
new file mode 100644
index 0000000..978c96f
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_poc/sandbox.rc
@@ -0,0 +1,136 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU_MAIN_UI MENU 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "E&xit",                       ID_FILE_EXIT
+    END
+    POPUP "&Commands"
+    BEGIN
+        MENUITEM "&Spawn target",               ID_COMMANDS_SPAWNTARGET
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_LAUNCH_DLL DIALOGEX 0, 0, 269, 118
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "BrokerUI: Load an Attack DLL"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "Call now",IDOK,212,70,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,212,95,50,14
+    EDITTEXT        IDC_DLL_NAME,7,43,200,13,ES_AUTOHSCROLL
+    LTEXT           "DLL to load in target:",IDC_STATIC,7,33,168,8
+    LTEXT           "Function to call:",IDC_STATIC,7,61,139,8
+    EDITTEXT        IDC_ENTRY_POINT,7,71,200,13,ES_AUTOHSCROLL
+    EDITTEXT        IDC_LOG_FILE,7,17,200,13,ES_AUTOHSCROLL
+    LTEXT           "File for Target logging (optional):",IDC_STATIC,7,7,139,8
+    PUSHBUTTON      "Browse...",IDC_BROWSE_DLL,212,42,50,14
+    PUSHBUTTON      "Browse...",IDC_BROWSE_LOG,212,16,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_LAUNCH_DLL, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 262
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 111
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SANDBOX             ICON                    "sandbox.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/libchrome/sandbox/win/sandbox_poc/sandbox_poc.vcproj b/libchrome/sandbox/win/sandbox_poc/sandbox_poc.vcproj
new file mode 100644
index 0000000..5fde1cd
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_poc/sandbox_poc.vcproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sandbox_poc"
+	ProjectGUID="{CF757839-F2A1-417C-8F25-DCAE480020F1}"
+	RootNamespace="sandbox_poc"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="comctl32.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="comctl32.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\main_ui_window.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\main_ui_window.h"
+			>
+		</File>
+		<File
+			RelativePath=".\resource.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.ico"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.rc"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/sandbox_standalone.sln b/libchrome/sandbox/win/sandbox_standalone.sln
new file mode 100644
index 0000000..529d20e
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_standalone.sln
@@ -0,0 +1,127 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox", "src\sandbox.vcproj", "{881F6A97-D539-4C48-B401-DF04385B2343}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_unittests", "tests\unit_tests\sbox_unittests.vcproj", "{883553BE-2A9D-418C-A121-61FE1DFBC562}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_validation_tests", "tests\validation_tests\sbox_validation_tests.vcproj", "{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
+	EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dependencies", "dependencies", "{BCE54389-D18D-48B9-977E-9D1998200F63}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debug_message", "..\base\debug_message.vcproj", "{F0F92189-193A-6607-C2BB-0F98BBD19ADF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{7F36EE20-5016-4051-B0D7-42824CDA0291}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "proof_of_concept", "proof_of_concept", "{B607BE7B-3555-422C-A40B-28E73C0B5E24}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sandbox_poc", "sandbox_poc\sandbox_poc.vcproj", "{CF757839-F2A1-417C-8F25-DCAE480020F1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224} = {AE5BFB87-850E-4454-B01D-58E7D8BAC224}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pocdll", "sandbox_poc\pocdll\pocdll.vcproj", "{AE5BFB87-850E-4454-B01D-58E7D8BAC224}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "finder", "tools\finder\finder.vcproj", "{ACDC2E06-0366-41A4-A646-C37E130A605D}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "tools\launcher\launcher.vcproj", "{386FA217-FBC2-4461-882D-CDAD221ED800}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sbox_integration_tests", "tests\integration_tests\sbox_integration_tests.vcproj", "{542D4B3B-98D4-4233-B68D-0103891508C6}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {1832A374-8A74-4F9E-B536-69A699B3E165}
+		{881F6A97-D539-4C48-B401-DF04385B2343} = {881F6A97-D539-4C48-B401-DF04385B2343}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "..\base\base.vcproj", "{1832A374-8A74-4F9E-B536-69A699B3E165}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "..\testing\gtest.vcproj", "{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Debug|Win32.ActiveCfg = Debug|Win32
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Debug|Win32.Build.0 = Debug|Win32
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Release|Win32.ActiveCfg = Release|Win32
+		{881F6A97-D539-4C48-B401-DF04385B2343}.Release|Win32.Build.0 = Release|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Debug|Win32.ActiveCfg = Debug|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Debug|Win32.Build.0 = Debug|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Release|Win32.ActiveCfg = Release|Win32
+		{883553BE-2A9D-418C-A121-61FE1DFBC562}.Release|Win32.Build.0 = Release|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Debug|Win32.Build.0 = Debug|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Release|Win32.ActiveCfg = Release|Win32
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}.Release|Win32.Build.0 = Release|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Debug|Win32.Build.0 = Debug|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Release|Win32.ActiveCfg = Release|Win32
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF}.Release|Win32.Build.0 = Release|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Debug|Win32.Build.0 = Debug|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Release|Win32.ActiveCfg = Release|Win32
+		{CF757839-F2A1-417C-8F25-DCAE480020F1}.Release|Win32.Build.0 = Release|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Debug|Win32.ActiveCfg = Debug|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Debug|Win32.Build.0 = Debug|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Release|Win32.ActiveCfg = Release|Win32
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224}.Release|Win32.Build.0 = Release|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Debug|Win32.Build.0 = Debug|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Release|Win32.ActiveCfg = Release|Win32
+		{ACDC2E06-0366-41A4-A646-C37E130A605D}.Release|Win32.Build.0 = Release|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Debug|Win32.ActiveCfg = Debug|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Debug|Win32.Build.0 = Debug|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Release|Win32.ActiveCfg = Release|Win32
+		{386FA217-FBC2-4461-882D-CDAD221ED800}.Release|Win32.Build.0 = Release|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Debug|Win32.ActiveCfg = Debug|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Debug|Win32.Build.0 = Debug|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Release|Win32.ActiveCfg = Release|Win32
+		{542D4B3B-98D4-4233-B68D-0103891508C6}.Release|Win32.Build.0 = Release|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.ActiveCfg = Debug|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Debug|Win32.Build.0 = Debug|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.ActiveCfg = Release|Win32
+		{1832A374-8A74-4F9E-B536-69A699B3E165}.Release|Win32.Build.0 = Release|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Debug|Win32.Build.0 = Debug|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Release|Win32.ActiveCfg = Release|Win32
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{883553BE-2A9D-418C-A121-61FE1DFBC562} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
+		{B9CC7B0D-145A-49C2-B887-84E43CFA0F27} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
+		{542D4B3B-98D4-4233-B68D-0103891508C6} = {F7A3B82E-B8B4-4FDF-BC8E-FEC9398F57ED}
+		{F0F92189-193A-6607-C2BB-0F98BBD19ADF} = {BCE54389-D18D-48B9-977E-9D1998200F63}
+		{1832A374-8A74-4F9E-B536-69A699B3E165} = {BCE54389-D18D-48B9-977E-9D1998200F63}
+		{BFE8E2A7-3B3B-43B0-A994-3058B852DB8B} = {BCE54389-D18D-48B9-977E-9D1998200F63}
+		{ACDC2E06-0366-41A4-A646-C37E130A605D} = {7F36EE20-5016-4051-B0D7-42824CDA0291}
+		{386FA217-FBC2-4461-882D-CDAD221ED800} = {7F36EE20-5016-4051-B0D7-42824CDA0291}
+		{CF757839-F2A1-417C-8F25-DCAE480020F1} = {B607BE7B-3555-422C-A40B-28E73C0B5E24}
+		{AE5BFB87-850E-4454-B01D-58E7D8BAC224} = {B607BE7B-3555-422C-A40B-28E73C0B5E24}
+	EndGlobalSection
+EndGlobal
diff --git a/libchrome/sandbox/win/sandbox_win.gypi b/libchrome/sandbox/win/sandbox_win.gypi
new file mode 100644
index 0000000..e9673aa
--- /dev/null
+++ b/libchrome/sandbox/win/sandbox_win.gypi
@@ -0,0 +1,432 @@
+# Copyright (c) 2012 The Chromium 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': {
+      'sandbox_windows_target': 0,
+      'target_arch%': 'ia32',
+    },
+    'target_conditions': [
+      ['sandbox_windows_target==1', {
+        # Files that are shared between the 32-bit and the 64-bit versions
+        # of the Windows sandbox library.
+        'sources': [
+            'src/acl.cc',
+            'src/acl.h',
+            'src/broker_services.cc',
+            'src/broker_services.h',
+            'src/crosscall_client.h',
+            'src/crosscall_params.h',
+            'src/crosscall_server.cc',
+            'src/crosscall_server.h',
+            'src/eat_resolver.cc',
+            'src/eat_resolver.h',
+            'src/filesystem_dispatcher.cc',
+            'src/filesystem_dispatcher.h',
+            'src/filesystem_interception.cc',
+            'src/filesystem_interception.h',
+            'src/filesystem_policy.cc',
+            'src/filesystem_policy.h',
+            'src/handle_closer.cc',
+            'src/handle_closer.h',
+            'src/handle_closer_agent.cc',
+            'src/handle_closer_agent.h',
+            'src/interception.cc',
+            'src/interception.h',
+            'src/interception_agent.cc',
+            'src/interception_agent.h',
+            'src/interception_internal.h',
+            'src/interceptors.h',
+            'src/internal_types.h',
+            'src/ipc_tags.h',
+            'src/job.cc',
+            'src/job.h',
+            'src/named_pipe_dispatcher.cc',
+            'src/named_pipe_dispatcher.h',
+            'src/named_pipe_interception.cc',
+            'src/named_pipe_interception.h',
+            'src/named_pipe_policy.cc',
+            'src/named_pipe_policy.h',
+            'src/nt_internals.h',
+            'src/policy_broker.cc',
+            'src/policy_broker.h',
+            'src/policy_engine_opcodes.cc',
+            'src/policy_engine_opcodes.h',
+            'src/policy_engine_params.h',
+            'src/policy_engine_processor.cc',
+            'src/policy_engine_processor.h',
+            'src/policy_low_level.cc',
+            'src/policy_low_level.h',
+            'src/policy_params.h',
+            'src/policy_target.cc',
+            'src/policy_target.h',
+            'src/process_mitigations.cc',
+            'src/process_mitigations.h',
+            'src/process_mitigations_win32k_dispatcher.cc',
+            'src/process_mitigations_win32k_dispatcher.h',
+            'src/process_mitigations_win32k_interception.cc',
+            'src/process_mitigations_win32k_interception.h',
+            'src/process_mitigations_win32k_policy.cc',
+            'src/process_mitigations_win32k_policy.h',
+            'src/process_thread_dispatcher.cc',
+            'src/process_thread_dispatcher.h',
+            'src/process_thread_interception.cc',
+            'src/process_thread_interception.h',
+            'src/process_thread_policy.cc',
+            'src/process_thread_policy.h',
+            'src/registry_dispatcher.cc',
+            'src/registry_dispatcher.h',
+            'src/registry_interception.cc',
+            'src/registry_interception.h',
+            'src/registry_policy.cc',
+            'src/registry_policy.h',
+            'src/resolver.cc',
+            'src/resolver.h',
+            'src/restricted_token_utils.cc',
+            'src/restricted_token_utils.h',
+            'src/restricted_token.cc',
+            'src/restricted_token.h',
+            'src/sandbox_factory.h',
+            'src/sandbox_globals.cc',
+            'src/sandbox_nt_types.h',
+            'src/sandbox_nt_util.cc',
+            'src/sandbox_nt_util.h',
+            'src/sandbox_policy_base.cc',
+            'src/sandbox_policy_base.h',
+            'src/sandbox_policy.h',
+            'src/sandbox_rand.cc',
+            'src/sandbox_rand.h',
+            'src/sandbox_types.h',
+            'src/sandbox_utils.cc',
+            'src/sandbox_utils.h',
+            'src/sandbox.cc',
+            'src/sandbox.h',
+            'src/security_level.h',
+            'src/service_resolver.cc',
+            'src/service_resolver.h',
+            'src/sharedmem_ipc_client.cc',
+            'src/sharedmem_ipc_client.h',
+            'src/sharedmem_ipc_server.cc',
+            'src/sharedmem_ipc_server.h',
+            'src/sid.cc',
+            'src/sid.h',
+            'src/sync_dispatcher.cc',
+            'src/sync_dispatcher.h',
+            'src/sync_interception.cc',
+            'src/sync_interception.h',
+            'src/sync_policy.cc',
+            'src/sync_policy.h',
+            'src/target_interceptions.cc',
+            'src/target_interceptions.h',
+            'src/target_process.cc',
+            'src/target_process.h',
+            'src/target_services.cc',
+            'src/target_services.h',
+            'src/top_level_dispatcher.cc',
+            'src/top_level_dispatcher.h',
+            'src/win_utils.cc',
+            'src/win_utils.h',
+            'src/win2k_threadpool.cc',
+            'src/win2k_threadpool.h',
+            'src/window.cc',
+            'src/window.h',
+        ],
+        'target_conditions': [
+          ['target_arch=="x64"', {
+            'sources': [
+              'src/interceptors_64.cc',
+              'src/interceptors_64.h',
+              'src/resolver_64.cc',
+              'src/service_resolver_64.cc',
+            ],
+          }],
+          ['target_arch=="ia32"', {
+            'sources': [
+              'src/resolver_32.cc',
+              'src/service_resolver_32.cc',
+              'src/sidestep_resolver.cc',
+              'src/sidestep_resolver.h',
+              'src/sidestep\ia32_modrm_map.cpp',
+              'src/sidestep\ia32_opcode_map.cpp',
+              'src/sidestep\mini_disassembler_types.h',
+              'src/sidestep\mini_disassembler.cpp',
+              'src/sidestep\mini_disassembler.h',
+              'src/sidestep\preamble_patcher_with_stub.cpp',
+              'src/sidestep\preamble_patcher.h',
+            ],
+          }],
+        ],
+      }],
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'sandbox',
+      'type': 'static_library',
+      'variables': {
+        'sandbox_windows_target': 1,
+      },
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/base.gyp:base_static',
+      ],
+      'export_dependent_settings': [
+        '../base/base.gyp:base',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+      'target_conditions': [
+        ['target_arch=="ia32"', {
+          'copies': [
+            {
+              'destination': '<(PRODUCT_DIR)',
+              'files': [
+                'wow_helper/wow_helper.exe',
+                'wow_helper/wow_helper.pdb',
+              ],
+            },
+          ],
+        }],
+      ],
+    },
+    {
+      'target_name': 'sbox_integration_tests',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        'sbox_integration_test_hook_dll',
+        'sbox_integration_test_win_proc',
+        '../base/base.gyp:test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'src/address_sanitizer_test.cc',
+        'src/app_container_test.cc',
+        'src/file_policy_test.cc',
+        'src/handle_inheritance_test.cc',
+        'tests/integration_tests/integration_tests_test.cc',
+        'src/handle_closer_test.cc',
+        'src/integrity_level_test.cc',
+        'src/ipc_ping_test.cc',
+        'src/lpc_policy_test.cc',
+        'src/named_pipe_policy_test.cc',
+        'src/policy_target_test.cc',
+        'src/process_mitigations_test.cc',
+        'src/process_policy_test.cc',
+        'src/registry_policy_test.cc',
+        'src/restricted_token_test.cc',
+        'src/sync_policy_test.cc',
+        'src/sync_policy_test.h',
+        'src/unload_dll_test.cc',
+        'tests/common/controller.cc',
+        'tests/common/controller.h',
+        'tests/common/test_utils.cc',
+        'tests/common/test_utils.h',
+        'tests/integration_tests/integration_tests.cc',
+        'tests/integration_tests/integration_tests_common.h',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-ldxva2.lib',
+        ],
+      },
+    },
+    {
+      'target_name': 'sbox_integration_test_hook_dll',
+      'type': 'shared_library',
+      'dependencies': [
+      ],
+      'sources': [
+        'tests/integration_tests/hooking_dll.cc',
+        'tests/integration_tests/integration_tests_common.h',
+      ],
+    },
+    {
+      'target_name': 'sbox_integration_test_win_proc',
+      'type': 'executable',
+      'dependencies': [
+      ],
+      'sources': [
+        'tests/integration_tests/hooking_win_proc.cc',
+        'tests/integration_tests/integration_tests_common.h',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '2',  # Set /SUBSYSTEM:WINDOWS
+        },
+      },
+    },
+    {
+      'target_name': 'sbox_validation_tests',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        '../base/base.gyp:test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'tests/common/controller.cc',
+        'tests/common/controller.h',
+        'tests/validation_tests/unit_tests.cc',
+        'tests/validation_tests/commands.cc',
+        'tests/validation_tests/commands.h',
+        'tests/validation_tests/suite.cc',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lshlwapi.lib',
+        ],
+      },
+    },
+    {
+      'target_name': 'sbox_unittests',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        '../base/base.gyp:test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'src/interception_unittest.cc',
+        'src/service_resolver_unittest.cc',
+        'src/restricted_token_unittest.cc',
+        'src/job_unittest.cc',
+        'src/sid_unittest.cc',
+        'src/policy_engine_unittest.cc',
+        'src/policy_low_level_unittest.cc',
+        'src/policy_opcodes_unittest.cc',
+        'src/ipc_unittest.cc',
+        'src/sandbox_nt_util_unittest.cc',
+        'src/threadpool_unittest.cc',
+        'src/win_utils_unittest.cc',
+        'tests/common/test_utils.cc',
+        'tests/common/test_utils.h',
+        'tests/unit_tests/unit_tests.cc',
+      ],
+    },
+    {
+      'target_name': 'sandbox_poc',
+      'type': 'executable',
+      'dependencies': [
+        'sandbox',
+        'pocdll',
+      ],
+      'sources': [
+        'sandbox_poc/main_ui_window.cc',
+        'sandbox_poc/main_ui_window.h',
+        'sandbox_poc/resource.h',
+        'sandbox_poc/sandbox.cc',
+        'sandbox_poc/sandbox.h',
+        'sandbox_poc/sandbox.ico',
+        'sandbox_poc/sandbox.rc',
+      ],
+      'link_settings': {
+        'libraries': [
+          '-lcomctl32.lib',
+        ],
+      },
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+        },
+      },
+    },
+    {
+      'target_name': 'pocdll',
+      'type': 'shared_library',
+      'sources': [
+        'sandbox_poc/pocdll/exports.h',
+        'sandbox_poc/pocdll/fs.cc',
+        'sandbox_poc/pocdll/handles.cc',
+        'sandbox_poc/pocdll/invasive.cc',
+        'sandbox_poc/pocdll/network.cc',
+        'sandbox_poc/pocdll/pocdll.cc',
+        'sandbox_poc/pocdll/processes_and_threads.cc',
+        'sandbox_poc/pocdll/registry.cc',
+        'sandbox_poc/pocdll/spyware.cc',
+        'sandbox_poc/pocdll/utils.h',
+      ],
+      'defines': [
+        'POCDLL_EXPORTS',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="win" and target_arch=="ia32"', {
+      'targets': [
+        {
+          'target_name': 'sandbox_win64',
+          'type': 'static_library',
+          'variables': {
+            'sandbox_windows_target': 1,
+            'target_arch': 'x64',
+          },
+          'dependencies': [
+            '../base/base.gyp:base_win64',
+            '../base/base.gyp:base_static_win64',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+          'include_dirs': [
+            '../..',
+          ],
+          'defines': [
+            '<@(nacl_win64_defines)',
+          ]
+        },
+      ],
+    }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'sbox_integration_tests_run',
+          'type': 'none',
+          'dependencies': [
+            'sbox_integration_tests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sbox_integration_tests.isolate',
+          ],
+        },
+        {
+          'target_name': 'sbox_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'sbox_unittests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sbox_unittests.isolate',
+          ],
+        },
+        {
+          'target_name': 'sbox_validation_tests_run',
+          'type': 'none',
+          'dependencies': [
+            'sbox_validation_tests',
+          ],
+          'includes': [
+            '../../build/isolate.gypi',
+          ],
+          'sources': [
+            '../sbox_validation_tests.isolate',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/libchrome/sandbox/win/src/crosscall_client.h b/libchrome/sandbox/win/src/crosscall_client.h
new file mode 100644
index 0000000..60ff243
--- /dev/null
+++ b/libchrome/sandbox/win/src/crosscall_client.h
@@ -0,0 +1,526 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_CROSSCALL_CLIENT_H_
+#define SANDBOX_SRC_CROSSCALL_CLIENT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/sandbox.h"
+
+// This header defines the CrossCall(..) family of templated functions
+// Their purpose is to simulate the syntax of regular call but to generate
+// and IPC from the client-side.
+//
+// The basic pattern is to
+//   1) use template argument deduction to compute the size of each
+//      parameter and the appropriate copy method
+//   2) pack the parameters in the appropriate ActualCallParams< > object
+//   3) call the IPC interface IPCProvider::DoCall( )
+//
+// The general interface of CrossCall is:
+//  ResultCode CrossCall(IPCProvider& ipc_provider,
+//                       uint32_t tag,
+//                       const Par1& p1, const Par2& p2,...pn
+//                       CrossCallReturn* answer)
+//
+//  where:
+//    ipc_provider: is a specific implementation of the ipc transport see
+//                  sharedmem_ipc_server.h for an example.
+//    tag : is the unique id for this IPC call. Is used to route the call to
+//          the appropriate service.
+//    p1, p2,.. pn : The input parameters of the IPC. Use only simple types
+//                   and wide strings (can add support for others).
+//    answer : If the IPC was successful. The server-side answer is here. The
+//             interpretation of the answer is private to client and server.
+//
+// The return value is ALL_OK if the IPC was delivered to the server, other
+// return codes indicate that the IPC transport failed to deliver it.
+namespace sandbox {
+
+// this is the assumed channel size. This can be overridden in a given
+// IPC implementation.
+const uint32_t kIPCChannelSize = 1024;
+
+// The copy helper uses templates to deduce the appropriate copy function to
+// copy the input parameters in the buffer that is going to be send across the
+// IPC. These template facility can be made more sophisticated as need arises.
+
+// The default copy helper. It catches the general case where no other
+// specialized template matches better. We set the type to UINT32_TYPE, so this
+// only works with objects whose size is 32 bits.
+template<typename T>
+class CopyHelper {
+ public:
+  CopyHelper(const T& t) : t_(t) {}
+
+  // Returns the pointer to the start of the input.
+  const void* GetStart() const {
+    return &t_;
+  }
+
+  // Update the stored value with the value in the buffer. This is not
+  // supported for this type.
+  bool Update(void* buffer) {
+    // Not supported;
+    return true;
+  }
+
+  // Returns the size of the input in bytes.
+  uint32_t GetSize() const { return sizeof(T); }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return false;
+  }
+
+  // Returns this object's type.
+  ArgType GetType() {
+    static_assert(sizeof(T) == sizeof(uint32_t), "specialization needed");
+    return UINT32_TYPE;
+  }
+
+ private:
+  const T& t_;
+};
+
+// This copy helper template specialization if for the void pointer
+// case both 32 and 64 bit.
+template<>
+class CopyHelper<void*> {
+ public:
+  CopyHelper(void* t) : t_(t) {}
+
+  // Returns the pointer to the start of the input.
+  const void* GetStart() const {
+    return &t_;
+  }
+
+  // Update the stored value with the value in the buffer. This is not
+  // supported for this type.
+  bool Update(void* buffer) {
+    // Not supported;
+    return true;
+  }
+
+  // Returns the size of the input in bytes.
+  uint32_t GetSize() const { return sizeof(t_); }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return false;
+  }
+
+  // Returns this object's type.
+  ArgType GetType() {
+    return VOIDPTR_TYPE;
+  }
+
+ private:
+  const void* t_;
+};
+
+// This copy helper template specialization catches the cases where the
+// parameter is a pointer to a string.
+template<>
+class CopyHelper<const wchar_t*> {
+ public:
+  CopyHelper(const wchar_t* t)
+      : t_(t) {
+  }
+
+  // Returns the pointer to the start of the string.
+  const void* GetStart() const {
+    return t_;
+  }
+
+  // Update the stored value with the value in the buffer. This is not
+  // supported for this type.
+  bool Update(void* buffer) {
+    // Not supported;
+    return true;
+  }
+
+  // Returns the size of the string in bytes. We define a NULL string to
+  // be of zero length.
+  uint32_t GetSize() const {
+    __try {
+      return (!t_) ? 0
+                   : static_cast<uint32_t>(StringLength(t_) * sizeof(t_[0]));
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER) {
+      return UINT32_MAX;
+    }
+  }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return false;
+  }
+
+  ArgType GetType() {
+    return WCHAR_TYPE;
+  }
+
+ private:
+  // We provide our not very optimized version of wcslen(), since we don't
+  // want to risk having the linker use the version in the CRT since the CRT
+  // might not be present when we do an early IPC call.
+  static size_t __cdecl StringLength(const wchar_t* wcs) {
+    const wchar_t *eos = wcs;
+    while (*eos++);
+    return static_cast<size_t>(eos - wcs - 1);
+  }
+
+  const wchar_t* t_;
+};
+
+// Specialization for non-const strings. We just reuse the implementation of the
+// const string specialization.
+template<>
+class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
+ public:
+  typedef CopyHelper<const wchar_t*> Base;
+  CopyHelper(wchar_t* t) : Base(t) {}
+
+  const void* GetStart() const {
+    return Base::GetStart();
+  }
+
+  bool Update(void* buffer) {
+    return Base::Update(buffer);
+  }
+
+  uint32_t GetSize() const { return Base::GetSize(); }
+
+  bool IsInOut() {
+    return Base::IsInOut();
+  }
+
+  ArgType GetType() {
+    return Base::GetType();
+  }
+};
+
+// Specialization for wchar_t arrays strings. We just reuse the implementation
+// of the const string specialization.
+template<size_t n>
+class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
+ public:
+  typedef const wchar_t array[n];
+  typedef CopyHelper<const wchar_t*> Base;
+  CopyHelper(array t) : Base(t) {}
+
+  const void* GetStart() const {
+    return Base::GetStart();
+  }
+
+  bool Update(void* buffer) {
+    return Base::Update(buffer);
+  }
+
+  uint32_t GetSize() const { return Base::GetSize(); }
+
+  bool IsInOut() {
+    return Base::IsInOut();
+  }
+
+  ArgType GetType() {
+    return Base::GetType();
+  }
+};
+
+// Generic encapsulation class containing a pointer to a buffer and the
+// size of the buffer. It is used by the IPC to be able to pass in/out
+// parameters.
+class InOutCountedBuffer : public CountedBuffer {
+ public:
+  InOutCountedBuffer(void* buffer, uint32_t size)
+      : CountedBuffer(buffer, size) {}
+};
+
+// This copy helper template specialization catches the cases where the
+// parameter is a an input/output buffer.
+template<>
+class CopyHelper<InOutCountedBuffer> {
+ public:
+  CopyHelper(const InOutCountedBuffer t) : t_(t) {}
+
+  // Returns the pointer to the start of the string.
+  const void* GetStart() const {
+    return t_.Buffer();
+  }
+
+  // Updates the buffer with the value from the new buffer in parameter.
+  bool Update(void* buffer) {
+    // We are touching user memory, this has to be done from inside a try
+    // except.
+    __try {
+      memcpy(t_.Buffer(), buffer, t_.Size());
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER) {
+      return false;
+    }
+    return true;
+  }
+
+  // Returns the size of the string in bytes. We define a NULL string to
+  // be of zero length.
+  uint32_t GetSize() const { return t_.Size(); }
+
+  // Returns true if the current type is used as an In or InOut parameter.
+  bool IsInOut() {
+    return true;
+  }
+
+  ArgType GetType() {
+    return INOUTPTR_TYPE;
+  }
+
+ private:
+  const InOutCountedBuffer t_;
+};
+
+// The following two macros make it less error prone the generation
+// of CrossCall functions with ever more input parameters.
+
+#define XCALL_GEN_PARAMS_OBJ(num, params) \
+  typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \
+  void* raw_mem = ipc_provider.GetBuffer(); \
+  if (NULL == raw_mem) \
+    return SBOX_ERROR_NO_SPACE; \
+  ActualParams* params = new(raw_mem) ActualParams(tag);
+
+#define XCALL_GEN_COPY_PARAM(num, params) \
+  static_assert(kMaxIpcParams >= num, "too many parameters"); \
+  CopyHelper<Par##num> ch##num(p##num); \
+  if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \
+                           ch##num.IsInOut(), ch##num.GetType())) \
+    return SBOX_ERROR_NO_SPACE;
+
+#define XCALL_GEN_UPDATE_PARAM(num, params) \
+  if (!ch##num.Update(params->GetParamPtr(num-1))) {\
+    ipc_provider.FreeBuffer(raw_mem); \
+    return SBOX_ERROR_BAD_PARAMS; \
+  }
+
+#define XCALL_GEN_FREE_CHANNEL() \
+  ipc_provider.FreeBuffer(raw_mem);
+
+// CrossCall template with one input parameter
+template <typename IPCProvider, typename Par1>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(1, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+
+  return result;
+}
+
+// CrossCall template with two input parameters.
+template <typename IPCProvider, typename Par1, typename Par2>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(2, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with three input parameters.
+template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(3, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with four input parameters.
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
+          typename Par4>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(4, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with five input parameters.
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
+          typename Par4,
+          typename Par5>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
+                     const Par5& p5,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(5, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+  XCALL_GEN_COPY_PARAM(5, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_UPDATE_PARAM(5, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with six input parameters.
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
+          typename Par4,
+          typename Par5,
+          typename Par6>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
+                     const Par5& p5,
+                     const Par6& p6,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(6, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+  XCALL_GEN_COPY_PARAM(5, call_params);
+  XCALL_GEN_COPY_PARAM(6, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_UPDATE_PARAM(5, call_params);
+    XCALL_GEN_UPDATE_PARAM(6, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+
+// CrossCall template with seven input parameters.
+template <typename IPCProvider,
+          typename Par1,
+          typename Par2,
+          typename Par3,
+          typename Par4,
+          typename Par5,
+          typename Par6,
+          typename Par7>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+                     uint32_t tag,
+                     const Par1& p1,
+                     const Par2& p2,
+                     const Par3& p3,
+                     const Par4& p4,
+                     const Par5& p5,
+                     const Par6& p6,
+                     const Par7& p7,
+                     CrossCallReturn* answer) {
+  XCALL_GEN_PARAMS_OBJ(7, call_params);
+  XCALL_GEN_COPY_PARAM(1, call_params);
+  XCALL_GEN_COPY_PARAM(2, call_params);
+  XCALL_GEN_COPY_PARAM(3, call_params);
+  XCALL_GEN_COPY_PARAM(4, call_params);
+  XCALL_GEN_COPY_PARAM(5, call_params);
+  XCALL_GEN_COPY_PARAM(6, call_params);
+  XCALL_GEN_COPY_PARAM(7, call_params);
+
+  ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+  if (SBOX_ERROR_CHANNEL_ERROR != result) {
+    XCALL_GEN_UPDATE_PARAM(1, call_params);
+    XCALL_GEN_UPDATE_PARAM(2, call_params);
+    XCALL_GEN_UPDATE_PARAM(3, call_params);
+    XCALL_GEN_UPDATE_PARAM(4, call_params);
+    XCALL_GEN_UPDATE_PARAM(5, call_params);
+    XCALL_GEN_UPDATE_PARAM(6, call_params);
+    XCALL_GEN_UPDATE_PARAM(7, call_params);
+    XCALL_GEN_FREE_CHANNEL();
+  }
+  return result;
+}
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_CROSSCALL_CLIENT_H__
diff --git a/libchrome/sandbox/win/src/crosscall_params.h b/libchrome/sandbox/win/src/crosscall_params.h
new file mode 100644
index 0000000..eb59c44
--- /dev/null
+++ b/libchrome/sandbox/win/src/crosscall_params.h
@@ -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.
+
+#ifndef SANDBOX_SRC_CROSSCALL_PARAMS_H__
+#define SANDBOX_SRC_CROSSCALL_PARAMS_H__
+
+#include <windows.h>
+#include <lmaccess.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+// Increases |value| until there is no need for padding given an int64_t
+// alignment. Returns the increased value.
+inline uint32_t Align(uint32_t value) {
+  uint32_t alignment = sizeof(int64_t);
+  return ((value + alignment - 1) / alignment) * alignment;
+}
+
+// This header is part of CrossCall: the sandbox inter-process communication.
+// This header defines the basic types used both in the client IPC and in the
+// server IPC code. CrossCallParams and ActualCallParams model the input
+// parameters of an IPC call and CrossCallReturn models the output params and
+// the return value.
+//
+// An IPC call is defined by its 'tag' which is a (uint32_t) unique identifier
+// that is used to route the IPC call to the proper server. Every tag implies
+// a complete call signature including the order and type of each parameter.
+//
+// Like most IPC systems. CrossCall is designed to take as inputs 'simple'
+// types such as integers and strings. Classes, generic arrays or pointers to
+// them are not supported.
+//
+// Another limitation of CrossCall is that the return value and output
+// parameters can only be uint32_t integers. Returning complex structures or
+// strings is not supported.
+
+namespace sandbox {
+
+// max number of extended return parameters. See CrossCallReturn
+const size_t kExtendedReturnCount = 8;
+
+// Union of multiple types to be used as extended results
+// in the CrossCallReturn.
+union MultiType {
+  uint32_t unsigned_int;
+  void* pointer;
+  HANDLE handle;
+  ULONG_PTR ulong_ptr;
+};
+
+// Maximum number of IPC parameters currently supported.
+// To increase this value, we have to:
+//  - Add another Callback typedef to Dispatcher.
+//  - Add another case to the switch on SharedMemIPCServer::InvokeCallback.
+//  - Add another case to the switch in GetActualAndMaxBufferSize
+const int kMaxIpcParams = 9;
+
+// Contains the information about a parameter in the ipc buffer.
+struct ParamInfo {
+  ArgType type_;
+  uint32_t offset_;
+  uint32_t size_;
+};
+
+// Models the return value and the return parameters of an IPC call
+// currently limited to one status code and eight generic return values
+// which cannot be pointers to other data. For x64 ports this structure
+// might have to use other integer types.
+struct CrossCallReturn {
+  // the IPC tag. It should match the original IPC tag.
+  uint32_t tag;
+  // The result of the IPC operation itself.
+  ResultCode call_outcome;
+  // the result of the IPC call as executed in the server. The interpretation
+  // of this value depends on the specific service.
+  union {
+    NTSTATUS nt_status;
+    DWORD    win32_result;
+  };
+  // Number of extended return values.
+  uint32_t extended_count;
+  // for calls that should return a windows handle. It is found here.
+  HANDLE handle;
+  // The array of extended values.
+  MultiType extended[kExtendedReturnCount];
+};
+
+// CrossCallParams base class that models the input params all packed in a
+// single compact memory blob. The representation can vary but in general a
+// given child of this class is meant to represent all input parameters
+// necessary to make a IPC call.
+//
+// This class cannot have virtual members because its assumed the IPC
+// parameters start from the 'this' pointer to the end, which is defined by
+// one of the subclasses
+//
+// Objects of this class cannot be constructed directly. Only derived
+// classes have the proper knowledge to construct it.
+class CrossCallParams {
+ public:
+  // Returns the tag (ipc unique id) associated with this IPC.
+  uint32_t GetTag() const { return tag_; }
+
+  // Returns the beggining of the buffer where the IPC params can be stored.
+  // prior to an IPC call
+  const void* GetBuffer() const {
+    return this;
+  }
+
+  // Returns how many parameter this IPC call should have.
+  uint32_t GetParamsCount() const { return params_count_; }
+
+  // Returns a pointer to the CrossCallReturn structure.
+  CrossCallReturn* GetCallReturn() {
+    return &call_return;
+  }
+
+  // Returns TRUE if this call contains InOut parameters.
+  bool IsInOut() const { return (1 == is_in_out_); }
+
+  // Tells the CrossCall object if it contains InOut parameters.
+  void SetIsInOut(bool value) {
+    if (value)
+      is_in_out_ = 1;
+    else
+      is_in_out_ = 0;
+  }
+
+ protected:
+  // constructs the IPC call params. Called only from the derived classes
+  CrossCallParams(uint32_t tag, uint32_t params_count)
+      : tag_(tag), is_in_out_(0), params_count_(params_count) {}
+
+ private:
+  uint32_t tag_;
+  uint32_t is_in_out_;
+  CrossCallReturn call_return;
+  const uint32_t params_count_;
+  DISALLOW_COPY_AND_ASSIGN(CrossCallParams);
+};
+
+// ActualCallParams models an specific IPC call parameters with respect to the
+// storage allocation that the packed parameters should need.
+// NUMBER_PARAMS: the number of parameters, valid from 1 to N
+// BLOCK_SIZE: the total storage that the NUMBER_PARAMS parameters can take,
+// typically the block size is defined by the channel size of the underlying
+// ipc mechanism.
+// In practice this class is used to levergage C++ capacity to properly
+// calculate sizes and displacements given the possibility of the packed params
+// blob to be complex.
+//
+// As is, this class assumes that the layout of the blob is as follows. Assume
+// that NUMBER_PARAMS = 2 and a 32-bit build:
+//
+// [ tag                4 bytes]
+// [ IsOnOut            4 bytes]
+// [ call return       52 bytes]
+// [ params count       4 bytes]
+// [ parameter 0 type   4 bytes]
+// [ parameter 0 offset 4 bytes] ---delta to ---\
+// [ parameter 0 size   4 bytes]                |
+// [ parameter 1 type   4 bytes]                |
+// [ parameter 1 offset 4 bytes] ---------------|--\
+// [ parameter 1 size   4 bytes]                |  |
+// [ parameter 2 type   4 bytes]                |  |
+// [ parameter 2 offset 4 bytes] ----------------------\
+// [ parameter 2 size   4 bytes]                |  |   |
+// |---------------------------|                |  |   |
+// | value 0     (x bytes)     | <--------------/  |   |
+// | value 1     (y bytes)     | <-----------------/   |
+// |                           |                       |
+// | end of buffer             | <---------------------/
+// |---------------------------|
+//
+// Note that the actual number of params is NUMBER_PARAMS + 1
+// so that the size of each actual param can be computed from the difference
+// between one parameter and the next down. The offset of the last param
+// points to the end of the buffer and the type and size are undefined.
+//
+template <size_t NUMBER_PARAMS, size_t BLOCK_SIZE>
+class ActualCallParams : public CrossCallParams {
+ public:
+  // constructor. Pass the ipc unique tag as input
+  explicit ActualCallParams(uint32_t tag)
+      : CrossCallParams(tag, NUMBER_PARAMS) {
+    param_info_[0].offset_ =
+        static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
+  }
+
+  // Testing-only constructor. Allows setting the |number_params| to a
+  // wrong value.
+  ActualCallParams(uint32_t tag, uint32_t number_params)
+      : CrossCallParams(tag, number_params) {
+    param_info_[0].offset_ =
+        static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
+  }
+
+  // Testing-only method. Allows setting the apparent size to a wrong value.
+  // returns the previous size.
+  uint32_t OverrideSize(uint32_t new_size) {
+    uint32_t previous_size = param_info_[NUMBER_PARAMS].offset_;
+    param_info_[NUMBER_PARAMS].offset_ = new_size;
+    return previous_size;
+  }
+
+  // Copies each paramter into the internal buffer. For each you must supply:
+  // index: 0 for the first param, 1 for the next an so on
+  bool CopyParamIn(uint32_t index,
+                   const void* parameter_address,
+                   uint32_t size,
+                   bool is_in_out,
+                   ArgType type) {
+    if (index >= NUMBER_PARAMS) {
+      return false;
+    }
+
+    if (UINT32_MAX == size) {
+      // Memory error while getting the size.
+      return false;
+    }
+
+    if (size && !parameter_address) {
+      return false;
+    }
+
+    if ((size > sizeof(*this)) ||
+        (param_info_[index].offset_ > (sizeof(*this) - size))) {
+      // It does not fit, abort copy.
+      return false;
+    }
+
+    char* dest = reinterpret_cast<char*>(this) +  param_info_[index].offset_;
+
+    // We might be touching user memory, this has to be done from inside a try
+    // except.
+    __try {
+      memcpy(dest, parameter_address, size);
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER) {
+      return false;
+    }
+
+    // Set the flag to tell the broker to update the buffer once the call is
+    // made.
+    if (is_in_out)
+      SetIsInOut(true);
+
+    param_info_[index + 1].offset_ = Align(param_info_[index].offset_ +
+                                                size);
+    param_info_[index].size_ = size;
+    param_info_[index].type_ = type;
+    return true;
+  }
+
+  // Returns a pointer to a parameter in the memory section.
+  void* GetParamPtr(size_t index) {
+    return reinterpret_cast<char*>(this) + param_info_[index].offset_;
+  }
+
+  // Returns the total size of the buffer. Only valid once all the paramters
+  // have been copied in with CopyParamIn.
+  uint32_t GetSize() const { return param_info_[NUMBER_PARAMS].offset_; }
+
+ protected:
+  ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
+
+ private:
+  ParamInfo param_info_[NUMBER_PARAMS + 1];
+  char parameters_[BLOCK_SIZE - sizeof(CrossCallParams)
+                   - sizeof(ParamInfo) * (NUMBER_PARAMS + 1)];
+  DISALLOW_COPY_AND_ASSIGN(ActualCallParams);
+};
+
+static_assert(sizeof(ActualCallParams<1, 1024>) == 1024, "bad size buffer");
+static_assert(sizeof(ActualCallParams<2, 1024>) == 1024, "bad size buffer");
+static_assert(sizeof(ActualCallParams<3, 1024>) == 1024, "bad size buffer");
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_CROSSCALL_PARAMS_H__
diff --git a/libchrome/sandbox/win/src/interception_internal.h b/libchrome/sandbox/win/src/interception_internal.h
new file mode 100644
index 0000000..45a0557
--- /dev/null
+++ b/libchrome/sandbox/win/src/interception_internal.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2006-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.
+
+// Defines InterceptionManager, the class in charge of setting up interceptions
+// for the sandboxed process. For more details see:
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#ifndef SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
+#define SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
+
+#include <stddef.h>
+
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+const int kMaxThunkDataBytes = 64;
+
+enum InterceptorId;
+
+// The following structures contain variable size fields at the end, and will be
+// used to transfer information between two processes. In order to guarantee
+// our ability to follow the chain of structures, the alignment should be fixed,
+// hence this pragma.
+#pragma pack(push, 4)
+
+// Structures for the shared memory that contains patching information
+// for the InterceptionAgent.
+// A single interception:
+struct FunctionInfo {
+  size_t record_bytes;            // rounded to sizeof(size_t) bytes
+  InterceptionType type;
+  InterceptorId id;
+  const void* interceptor_address;
+  char function[1];               // placeholder for null terminated name
+  // char interceptor[]           // followed by the interceptor function
+};
+
+// A single dll:
+struct DllPatchInfo {
+  size_t record_bytes;            // rounded to sizeof(size_t) bytes
+  size_t offset_to_functions;
+  int num_functions;
+  bool unload_module;
+  wchar_t dll_name[1];            // placeholder for null terminated name
+  // FunctionInfo function_info[] // followed by the functions to intercept
+};
+
+// All interceptions:
+struct SharedMemory {
+  int num_intercepted_dlls;
+  void* interceptor_base;
+  DllPatchInfo dll_list[1];       // placeholder for the list of dlls
+};
+
+// Dummy single thunk:
+struct ThunkData {
+  char data[kMaxThunkDataBytes];
+};
+
+// In-memory representation of the interceptions for a given dll:
+struct DllInterceptionData {
+  size_t data_bytes;
+  size_t used_bytes;
+  void* base;
+  int num_thunks;
+#if defined(_WIN64)
+  int dummy;                      // Improve alignment.
+#endif
+  ThunkData thunks[1];
+};
+
+#pragma pack(pop)
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
diff --git a/libchrome/sandbox/win/src/interceptors.h b/libchrome/sandbox/win/src/interceptors.h
new file mode 100644
index 0000000..44b34e3
--- /dev/null
+++ b/libchrome/sandbox/win/src/interceptors.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.
+
+#ifndef SANDBOX_SRC_INTERCEPTORS_H_
+#define SANDBOX_SRC_INTERCEPTORS_H_
+
+#if defined(_WIN64)
+#include "sandbox/win/src/interceptors_64.h"
+#endif
+
+namespace sandbox {
+
+enum InterceptorId {
+  // Internal use:
+  MAP_VIEW_OF_SECTION_ID = 0,
+  UNMAP_VIEW_OF_SECTION_ID,
+  // Policy broker:
+  SET_INFORMATION_THREAD_ID,
+  OPEN_THREAD_TOKEN_ID,
+  OPEN_THREAD_TOKEN_EX_ID,
+  OPEN_THREAD_ID,
+  OPEN_PROCESS_ID,
+  OPEN_PROCESS_TOKEN_ID,
+  OPEN_PROCESS_TOKEN_EX_ID,
+  // Filesystem dispatcher:
+  CREATE_FILE_ID,
+  OPEN_FILE_ID,
+  QUERY_ATTRIB_FILE_ID,
+  QUERY_FULL_ATTRIB_FILE_ID,
+  SET_INFO_FILE_ID,
+  // Named pipe dispatcher:
+  CREATE_NAMED_PIPE_ID,
+  // Process-thread dispatcher:
+  CREATE_PROCESSW_ID,
+  CREATE_PROCESSA_ID,
+  CREATE_THREAD_ID,
+  // Registry dispatcher:
+  CREATE_KEY_ID,
+  OPEN_KEY_ID,
+  OPEN_KEY_EX_ID,
+  // Sync dispatcher:
+  CREATE_EVENT_ID,
+  OPEN_EVENT_ID,
+  // Process mitigations Win32k dispatcher:
+  GDIINITIALIZE_ID,
+  GETSTOCKOBJECT_ID,
+  REGISTERCLASSW_ID,
+  ENUMDISPLAYMONITORS_ID,
+  ENUMDISPLAYDEVICESA_ID,
+  GETMONITORINFOA_ID,
+  GETMONITORINFOW_ID,
+  CREATEOPMPROTECTEDOUTPUTS_ID,
+  GETCERTIFICATE_ID,
+  GETCERTIFICATESIZE_ID,
+  GETCERTIFICATEBYHANDLE_ID,
+  GETCERTIFICATESIZEBYHANDLE_ID,
+  DESTROYOPMPROTECTEDOUTPUT_ID,
+  CONFIGUREOPMPROTECTEDOUTPUT_ID,
+  GETOPMINFORMATION_ID,
+  GETOPMRANDOMNUMBER_ID,
+  GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_ID,
+  SETOPMSIGNINGKEYANDSEQUENCENUMBERS_ID,
+  INTERCEPTOR_MAX_ID
+};
+
+typedef void* OriginalFunctions[INTERCEPTOR_MAX_ID];
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_INTERCEPTORS_H_
diff --git a/libchrome/sandbox/win/src/internal_types.h b/libchrome/sandbox/win/src/internal_types.h
new file mode 100644
index 0000000..e102818
--- /dev/null
+++ b/libchrome/sandbox/win/src/internal_types.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 SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
+#define SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
+
+#include <stdint.h>
+
+namespace sandbox {
+
+const wchar_t kNtdllName[] = L"ntdll.dll";
+const wchar_t kKerneldllName[] = L"kernel32.dll";
+const wchar_t kKernelBasedllName[] = L"kernelbase.dll";
+
+// Defines the supported C++ types encoding to numeric id. Like a poor's man
+// RTTI. Note that true C++ RTTI will not work because the types are not
+// polymorphic anyway.
+enum ArgType {
+  INVALID_TYPE = 0,
+  WCHAR_TYPE,
+  UINT32_TYPE,
+  UNISTR_TYPE,
+  VOIDPTR_TYPE,
+  INPTR_TYPE,
+  INOUTPTR_TYPE,
+  LAST_TYPE
+};
+
+// Encapsulates a pointer to a buffer and the size of the buffer.
+class CountedBuffer {
+ public:
+  CountedBuffer(void* buffer, uint32_t size) : size_(size), buffer_(buffer) {}
+
+  uint32_t Size() const { return size_; }
+
+  void* Buffer() const {
+    return buffer_;
+  }
+
+ private:
+  uint32_t size_;
+  void* buffer_;
+};
+
+// Helper class to convert void-pointer packed ints for both
+// 32 and 64 bit builds. This construct is non-portable.
+class IPCInt {
+ public:
+  explicit IPCInt(void* buffer) {
+    buffer_.vp = buffer;
+  }
+
+  explicit IPCInt(unsigned __int32 i32) {
+    buffer_.vp = NULL;
+    buffer_.i32 = i32;
+  }
+
+  unsigned __int32 As32Bit() const {
+    return buffer_.i32;
+  }
+
+  void* AsVoidPtr() const {
+    return buffer_.vp;
+  }
+
+ private:
+  union U {
+    void* vp;
+    unsigned __int32 i32;
+  } buffer_;
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
diff --git a/libchrome/sandbox/win/src/ipc_tags.h b/libchrome/sandbox/win/src/ipc_tags.h
new file mode 100644
index 0000000..1c754cd
--- /dev/null
+++ b/libchrome/sandbox/win/src/ipc_tags.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 SANDBOX_SRC_IPC_TAGS_H__
+#define SANDBOX_SRC_IPC_TAGS_H__
+
+namespace sandbox {
+
+enum {
+  IPC_UNUSED_TAG = 0,
+  IPC_PING1_TAG,  // Takes a cookie in parameters and returns the cookie
+                  // multiplied by 2 and the tick_count. Used for testing only.
+  IPC_PING2_TAG,  // Takes an in/out cookie in parameters and modify the cookie
+                  // to be multiplied by 3. Used for testing only.
+  IPC_NTCREATEFILE_TAG,
+  IPC_NTOPENFILE_TAG,
+  IPC_NTQUERYATTRIBUTESFILE_TAG,
+  IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
+  IPC_NTSETINFO_RENAME_TAG,
+  IPC_CREATENAMEDPIPEW_TAG,
+  IPC_NTOPENTHREAD_TAG,
+  IPC_NTOPENPROCESS_TAG,
+  IPC_NTOPENPROCESSTOKEN_TAG,
+  IPC_NTOPENPROCESSTOKENEX_TAG,
+  IPC_CREATEPROCESSW_TAG,
+  IPC_CREATEEVENT_TAG,
+  IPC_OPENEVENT_TAG,
+  IPC_NTCREATEKEY_TAG,
+  IPC_NTOPENKEY_TAG,
+  IPC_GDI_GDIDLLINITIALIZE_TAG,
+  IPC_GDI_GETSTOCKOBJECT_TAG,
+  IPC_USER_REGISTERCLASSW_TAG,
+  IPC_CREATETHREAD_TAG,
+  IPC_USER_ENUMDISPLAYMONITORS_TAG,
+  IPC_USER_ENUMDISPLAYDEVICES_TAG,
+  IPC_USER_GETMONITORINFO_TAG,
+  IPC_GDI_CREATEOPMPROTECTEDOUTPUTS_TAG,
+  IPC_GDI_GETCERTIFICATE_TAG,
+  IPC_GDI_GETCERTIFICATESIZE_TAG,
+  IPC_GDI_DESTROYOPMPROTECTEDOUTPUT_TAG,
+  IPC_GDI_CONFIGUREOPMPROTECTEDOUTPUT_TAG,
+  IPC_GDI_GETOPMINFORMATION_TAG,
+  IPC_GDI_GETOPMRANDOMNUMBER_TAG,
+  IPC_GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_TAG,
+  IPC_GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS_TAG,
+  IPC_LAST_TAG
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_IPC_TAGS_H__
diff --git a/libchrome/sandbox/win/src/nt_internals.h b/libchrome/sandbox/win/src/nt_internals.h
new file mode 100644
index 0000000..6469c2b
--- /dev/null
+++ b/libchrome/sandbox/win/src/nt_internals.h
@@ -0,0 +1,912 @@
+// 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 holds definitions related to the ntdll API.
+
+#ifndef SANDBOX_WIN_SRC_NT_INTERNALS_H__
+#define SANDBOX_WIN_SRC_NT_INTERNALS_H__
+
+#include <windows.h>
+#include <stddef.h>
+
+typedef LONG NTSTATUS;
+#define NT_SUCCESS(st) (st >= 0)
+
+#define STATUS_SUCCESS                ((NTSTATUS)0x00000000L)
+#define STATUS_BUFFER_OVERFLOW        ((NTSTATUS)0x80000005L)
+#define STATUS_UNSUCCESSFUL           ((NTSTATUS)0xC0000001L)
+#define STATUS_NOT_IMPLEMENTED        ((NTSTATUS)0xC0000002L)
+#define STATUS_INFO_LENGTH_MISMATCH   ((NTSTATUS)0xC0000004L)
+#ifndef STATUS_INVALID_PARAMETER
+// It is now defined in Windows 2008 SDK.
+#define STATUS_INVALID_PARAMETER      ((NTSTATUS)0xC000000DL)
+#endif
+#define STATUS_CONFLICTING_ADDRESSES  ((NTSTATUS)0xC0000018L)
+#define STATUS_ACCESS_DENIED          ((NTSTATUS)0xC0000022L)
+#define STATUS_BUFFER_TOO_SMALL       ((NTSTATUS)0xC0000023L)
+#define STATUS_OBJECT_NAME_NOT_FOUND  ((NTSTATUS)0xC0000034L)
+#define STATUS_OBJECT_NAME_COLLISION  ((NTSTATUS)0xC0000035L)
+#define STATUS_PROCEDURE_NOT_FOUND    ((NTSTATUS)0xC000007AL)
+#define STATUS_INVALID_IMAGE_FORMAT   ((NTSTATUS)0xC000007BL)
+#define STATUS_NO_TOKEN               ((NTSTATUS)0xC000007CL)
+#define STATUS_NOT_SUPPORTED          ((NTSTATUS)0xC00000BBL)
+
+#define CURRENT_PROCESS ((HANDLE) -1)
+#define CURRENT_THREAD  ((HANDLE) -2)
+#define NtCurrentProcess CURRENT_PROCESS
+
+typedef struct _UNICODE_STRING {
+  USHORT Length;
+  USHORT MaximumLength;
+  PWSTR  Buffer;
+} UNICODE_STRING;
+typedef UNICODE_STRING *PUNICODE_STRING;
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+typedef struct _STRING {
+  USHORT Length;
+  USHORT MaximumLength;
+  PCHAR Buffer;
+} STRING;
+typedef STRING *PSTRING;
+
+typedef STRING ANSI_STRING;
+typedef PSTRING PANSI_STRING;
+typedef CONST PSTRING PCANSI_STRING;
+
+typedef STRING OEM_STRING;
+typedef PSTRING POEM_STRING;
+typedef CONST STRING* PCOEM_STRING;
+
+#define OBJ_CASE_INSENSITIVE 0x00000040L
+#define OBJ_OPENIF           0x00000080L
+
+typedef struct _OBJECT_ATTRIBUTES {
+  ULONG Length;
+  HANDLE RootDirectory;
+  PUNICODE_STRING ObjectName;
+  ULONG Attributes;
+  PVOID SecurityDescriptor;
+  PVOID SecurityQualityOfService;
+} OBJECT_ATTRIBUTES;
+typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
+
+#define InitializeObjectAttributes(p, n, a, r, s) { \
+  (p)->Length = sizeof(OBJECT_ATTRIBUTES);\
+  (p)->RootDirectory = r;\
+  (p)->Attributes = a;\
+  (p)->ObjectName = n;\
+  (p)->SecurityDescriptor = s;\
+  (p)->SecurityQualityOfService = NULL;\
+}
+
+typedef struct _IO_STATUS_BLOCK {
+  union {
+    NTSTATUS Status;
+    PVOID Pointer;
+  };
+  ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+// -----------------------------------------------------------------------
+// File IO
+
+// Create disposition values.
+
+#define FILE_SUPERSEDE                          0x00000000
+#define FILE_OPEN                               0x00000001
+#define FILE_CREATE                             0x00000002
+#define FILE_OPEN_IF                            0x00000003
+#define FILE_OVERWRITE                          0x00000004
+#define FILE_OVERWRITE_IF                       0x00000005
+#define FILE_MAXIMUM_DISPOSITION                0x00000005
+
+// Create/open option flags.
+
+#define FILE_DIRECTORY_FILE                     0x00000001
+#define FILE_WRITE_THROUGH                      0x00000002
+#define FILE_SEQUENTIAL_ONLY                    0x00000004
+#define FILE_NO_INTERMEDIATE_BUFFERING          0x00000008
+
+#define FILE_SYNCHRONOUS_IO_ALERT               0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT            0x00000020
+#define FILE_NON_DIRECTORY_FILE                 0x00000040
+#define FILE_CREATE_TREE_CONNECTION             0x00000080
+
+#define FILE_COMPLETE_IF_OPLOCKED               0x00000100
+#define FILE_NO_EA_KNOWLEDGE                    0x00000200
+#define FILE_OPEN_REMOTE_INSTANCE               0x00000400
+#define FILE_RANDOM_ACCESS                      0x00000800
+
+#define FILE_DELETE_ON_CLOSE                    0x00001000
+#define FILE_OPEN_BY_FILE_ID                    0x00002000
+#define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
+#define FILE_NO_COMPRESSION                     0x00008000
+
+#define FILE_RESERVE_OPFILTER                   0x00100000
+#define FILE_OPEN_REPARSE_POINT                 0x00200000
+#define FILE_OPEN_NO_RECALL                     0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
+
+// Create/open result values. These are the disposition values returned on the
+// io status information.
+#define FILE_SUPERSEDED                         0x00000000
+#define FILE_OPENED                             0x00000001
+#define FILE_CREATED                            0x00000002
+#define FILE_OVERWRITTEN                        0x00000003
+#define FILE_EXISTS                             0x00000004
+#define FILE_DOES_NOT_EXIST                     0x00000005
+
+typedef NTSTATUS (WINAPI *NtCreateFileFunction)(
+  OUT PHANDLE FileHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PIO_STATUS_BLOCK IoStatusBlock,
+  IN PLARGE_INTEGER AllocationSize OPTIONAL,
+  IN ULONG FileAttributes,
+  IN ULONG ShareAccess,
+  IN ULONG CreateDisposition,
+  IN ULONG CreateOptions,
+  IN PVOID EaBuffer OPTIONAL,
+  IN ULONG EaLength);
+
+typedef NTSTATUS (WINAPI *NtOpenFileFunction)(
+  OUT PHANDLE FileHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PIO_STATUS_BLOCK IoStatusBlock,
+  IN ULONG ShareAccess,
+  IN ULONG OpenOptions);
+
+typedef NTSTATUS (WINAPI *NtCloseFunction)(
+  IN HANDLE Handle);
+
+typedef enum _FILE_INFORMATION_CLASS {
+  FileRenameInformation = 10
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_RENAME_INFORMATION {
+  BOOLEAN ReplaceIfExists;
+  HANDLE RootDirectory;
+  ULONG FileNameLength;
+  WCHAR FileName[1];
+} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtSetInformationFileFunction)(
+  IN HANDLE FileHandle,
+  OUT PIO_STATUS_BLOCK IoStatusBlock,
+  IN PVOID FileInformation,
+  IN ULONG Length,
+  IN FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef struct FILE_BASIC_INFORMATION {
+  LARGE_INTEGER CreationTime;
+  LARGE_INTEGER LastAccessTime;
+  LARGE_INTEGER LastWriteTime;
+  LARGE_INTEGER ChangeTime;
+  ULONG FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQueryAttributesFileFunction)(
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PFILE_BASIC_INFORMATION FileAttributes);
+
+typedef struct _FILE_NETWORK_OPEN_INFORMATION {
+  LARGE_INTEGER CreationTime;
+  LARGE_INTEGER LastAccessTime;
+  LARGE_INTEGER LastWriteTime;
+  LARGE_INTEGER ChangeTime;
+  LARGE_INTEGER AllocationSize;
+  LARGE_INTEGER EndOfFile;
+  ULONG FileAttributes;
+} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQueryFullAttributesFileFunction)(
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  OUT PFILE_NETWORK_OPEN_INFORMATION FileAttributes);
+
+// -----------------------------------------------------------------------
+// Sections
+
+typedef NTSTATUS (WINAPI *NtCreateSectionFunction)(
+  OUT PHANDLE SectionHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+  IN PLARGE_INTEGER MaximumSize OPTIONAL,
+  IN ULONG SectionPageProtection,
+  IN ULONG AllocationAttributes,
+  IN HANDLE FileHandle OPTIONAL);
+
+typedef ULONG SECTION_INHERIT;
+#define ViewShare 1
+#define ViewUnmap 2
+
+typedef NTSTATUS (WINAPI *NtMapViewOfSectionFunction)(
+  IN HANDLE SectionHandle,
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID *BaseAddress,
+  IN ULONG_PTR ZeroBits,
+  IN SIZE_T CommitSize,
+  IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
+  IN OUT PSIZE_T ViewSize,
+  IN SECTION_INHERIT InheritDisposition,
+  IN ULONG AllocationType,
+  IN ULONG Win32Protect);
+
+typedef NTSTATUS (WINAPI *NtUnmapViewOfSectionFunction)(
+  IN HANDLE ProcessHandle,
+  IN PVOID BaseAddress);
+
+typedef enum _SECTION_INFORMATION_CLASS {
+  SectionBasicInformation = 0,
+  SectionImageInformation
+} SECTION_INFORMATION_CLASS;
+
+typedef struct _SECTION_BASIC_INFORMATION {
+  PVOID BaseAddress;
+  ULONG Attributes;
+  LARGE_INTEGER Size;
+} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQuerySectionFunction)(
+  IN HANDLE SectionHandle,
+  IN SECTION_INFORMATION_CLASS SectionInformationClass,
+  OUT PVOID SectionInformation,
+  IN SIZE_T SectionInformationLength,
+  OUT PSIZE_T ReturnLength OPTIONAL);
+
+// -----------------------------------------------------------------------
+// Process and Thread
+
+typedef struct _CLIENT_ID {
+  PVOID UniqueProcess;
+  PVOID UniqueThread;
+} CLIENT_ID, *PCLIENT_ID;
+
+typedef NTSTATUS (WINAPI *NtOpenThreadFunction) (
+  OUT PHANDLE ThreadHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN PCLIENT_ID ClientId);
+
+typedef NTSTATUS (WINAPI *NtOpenProcessFunction) (
+  OUT PHANDLE ProcessHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN PCLIENT_ID ClientId);
+
+typedef enum _NT_THREAD_INFORMATION_CLASS {
+  ThreadBasicInformation,
+  ThreadTimes,
+  ThreadPriority,
+  ThreadBasePriority,
+  ThreadAffinityMask,
+  ThreadImpersonationToken,
+  ThreadDescriptorTableEntry,
+  ThreadEnableAlignmentFaultFixup,
+  ThreadEventPair,
+  ThreadQuerySetWin32StartAddress,
+  ThreadZeroTlsCell,
+  ThreadPerformanceCount,
+  ThreadAmILastThread,
+  ThreadIdealProcessor,
+  ThreadPriorityBoost,
+  ThreadSetTlsArrayAddress,
+  ThreadIsIoPending,
+  ThreadHideFromDebugger
+} NT_THREAD_INFORMATION_CLASS, *PNT_THREAD_INFORMATION_CLASS;
+
+typedef NTSTATUS (WINAPI *NtSetInformationThreadFunction) (
+  IN HANDLE ThreadHandle,
+  IN NT_THREAD_INFORMATION_CLASS ThreadInformationClass,
+  IN PVOID ThreadInformation,
+  IN ULONG ThreadInformationLength);
+
+// Partial definition only:
+typedef enum _PROCESSINFOCLASS {
+  ProcessBasicInformation = 0,
+  ProcessExecuteFlags = 0x22
+} PROCESSINFOCLASS;
+
+typedef PVOID PPEB;
+typedef LONG KPRIORITY;
+
+typedef struct _PROCESS_BASIC_INFORMATION {
+  union {
+    NTSTATUS ExitStatus;
+    PVOID padding_for_x64_0;
+  };
+  PPEB PebBaseAddress;
+  KAFFINITY AffinityMask;
+  union {
+    KPRIORITY BasePriority;
+    PVOID padding_for_x64_1;
+  };
+  union {
+    DWORD UniqueProcessId;
+    PVOID padding_for_x64_2;
+  };
+  union {
+    DWORD InheritedFromUniqueProcessId;
+    PVOID padding_for_x64_3;
+  };
+} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtQueryInformationProcessFunction)(
+    IN HANDLE ProcessHandle,
+    IN PROCESSINFOCLASS ProcessInformationClass,
+    OUT PVOID ProcessInformation,
+    IN ULONG ProcessInformationLength,
+    OUT PULONG ReturnLength OPTIONAL);
+
+typedef NTSTATUS(WINAPI* NtSetInformationProcessFunction)(
+    HANDLE ProcessHandle,
+    IN PROCESSINFOCLASS ProcessInformationClass,
+    IN PVOID ProcessInformation,
+    IN ULONG ProcessInformationLength);
+
+typedef NTSTATUS (WINAPI *NtOpenThreadTokenFunction) (
+  IN HANDLE ThreadHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN BOOLEAN OpenAsSelf,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS (WINAPI *NtOpenThreadTokenExFunction) (
+  IN HANDLE ThreadHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN BOOLEAN OpenAsSelf,
+  IN ULONG HandleAttributes,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS (WINAPI *NtOpenProcessTokenFunction) (
+  IN HANDLE ProcessHandle,
+  IN ACCESS_MASK DesiredAccess,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS (WINAPI *NtOpenProcessTokenExFunction) (
+  IN HANDLE ProcessHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN ULONG HandleAttributes,
+  OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS(WINAPI* NtQueryInformationTokenFunction)(
+    IN HANDLE TokenHandle,
+    IN TOKEN_INFORMATION_CLASS TokenInformationClass,
+    OUT PVOID TokenInformation,
+    IN ULONG TokenInformationLength,
+    OUT PULONG ReturnLength);
+
+typedef NTSTATUS(WINAPI* RtlCreateUserThreadFunction)(
+    IN HANDLE Process,
+    IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
+    IN BOOLEAN CreateSuspended,
+    IN ULONG ZeroBits,
+    IN SIZE_T MaximumStackSize,
+    IN SIZE_T CommittedStackSize,
+    IN LPTHREAD_START_ROUTINE StartAddress,
+    IN PVOID Parameter,
+    OUT PHANDLE Thread,
+    OUT PCLIENT_ID ClientId);
+
+typedef NTSTATUS(WINAPI* RtlConvertSidToUnicodeStringFunction)(
+    OUT PUNICODE_STRING UnicodeString,
+    IN PSID Sid,
+    IN BOOLEAN AllocateDestinationString);
+
+typedef VOID(WINAPI* RtlFreeUnicodeStringFunction)(
+    IN OUT PUNICODE_STRING UnicodeString);
+
+// -----------------------------------------------------------------------
+// Registry
+
+typedef enum _KEY_VALUE_INFORMATION_CLASS {
+  KeyValueFullInformation = 1
+} KEY_VALUE_INFORMATION_CLASS,
+    *PKEY_VALUE_INFORMATION_CLASS;
+
+typedef struct _KEY_VALUE_FULL_INFORMATION {
+  ULONG TitleIndex;
+  ULONG Type;
+  ULONG DataOffset;
+  ULONG DataLength;
+  ULONG NameLength;
+  WCHAR Name[1];
+} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtCreateKeyFunction)(
+  OUT PHANDLE KeyHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN ULONG TitleIndex,
+  IN PUNICODE_STRING Class OPTIONAL,
+  IN ULONG CreateOptions,
+  OUT PULONG Disposition OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtOpenKeyFunction)(
+  OUT PHANDLE KeyHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI *NtOpenKeyExFunction)(
+  OUT PHANDLE KeyHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes,
+  IN DWORD open_options);
+
+typedef NTSTATUS (WINAPI *NtDeleteKeyFunction)(
+  IN HANDLE KeyHandle);
+
+typedef NTSTATUS(WINAPI* RtlFormatCurrentUserKeyPathFunction)(
+    OUT PUNICODE_STRING RegistryPath);
+
+typedef NTSTATUS(WINAPI* NtQueryValueKeyFunction)(IN HANDLE KeyHandle,
+                                                  IN PUNICODE_STRING ValueName,
+                                                  IN KEY_VALUE_INFORMATION_CLASS
+                                                      KeyValueInformationClass,
+                                                  OUT PVOID KeyValueInformation,
+                                                  IN ULONG Length,
+                                                  OUT PULONG ResultLength);
+
+typedef NTSTATUS(WINAPI* NtSetValueKeyFunction)(IN HANDLE KeyHandle,
+                                                IN PUNICODE_STRING ValueName,
+                                                IN ULONG TitleIndex OPTIONAL,
+                                                IN ULONG Type,
+                                                IN PVOID Data,
+                                                IN ULONG DataSize);
+
+// -----------------------------------------------------------------------
+// Memory
+
+// Don't really need this structure right now.
+typedef PVOID PRTL_HEAP_PARAMETERS;
+
+typedef PVOID (WINAPI *RtlCreateHeapFunction)(
+  IN ULONG Flags,
+  IN PVOID HeapBase OPTIONAL,
+  IN SIZE_T ReserveSize OPTIONAL,
+  IN SIZE_T CommitSize OPTIONAL,
+  IN PVOID Lock OPTIONAL,
+  IN PRTL_HEAP_PARAMETERS Parameters OPTIONAL);
+
+typedef PVOID (WINAPI *RtlDestroyHeapFunction)(
+  IN PVOID HeapHandle);
+
+typedef PVOID (WINAPI *RtlAllocateHeapFunction)(
+  IN PVOID HeapHandle,
+  IN ULONG Flags,
+  IN SIZE_T Size);
+
+typedef BOOLEAN (WINAPI *RtlFreeHeapFunction)(
+  IN PVOID HeapHandle,
+  IN ULONG Flags,
+  IN PVOID HeapBase);
+
+typedef NTSTATUS (WINAPI *NtAllocateVirtualMemoryFunction) (
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID *BaseAddress,
+  IN ULONG_PTR ZeroBits,
+  IN OUT PSIZE_T RegionSize,
+  IN ULONG AllocationType,
+  IN ULONG Protect);
+
+typedef NTSTATUS (WINAPI *NtFreeVirtualMemoryFunction) (
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID *BaseAddress,
+  IN OUT PSIZE_T RegionSize,
+  IN ULONG FreeType);
+
+typedef enum _MEMORY_INFORMATION_CLASS {
+  MemoryBasicInformation = 0,
+  MemoryWorkingSetList,
+  MemorySectionName,
+  MemoryBasicVlmInformation
+} MEMORY_INFORMATION_CLASS;
+
+typedef struct _MEMORY_SECTION_NAME {  // Information Class 2
+  UNICODE_STRING SectionFileName;
+} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
+
+typedef NTSTATUS (WINAPI *NtQueryVirtualMemoryFunction)(
+  IN HANDLE ProcessHandle,
+  IN PVOID BaseAddress,
+  IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
+  OUT PVOID MemoryInformation,
+  IN SIZE_T MemoryInformationLength,
+  OUT PSIZE_T ReturnLength OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtProtectVirtualMemoryFunction)(
+  IN HANDLE ProcessHandle,
+  IN OUT PVOID* BaseAddress,
+  IN OUT PSIZE_T ProtectSize,
+  IN ULONG NewProtect,
+  OUT PULONG OldProtect);
+
+// -----------------------------------------------------------------------
+// Objects
+
+typedef enum _OBJECT_INFORMATION_CLASS {
+  ObjectBasicInformation,
+  ObjectNameInformation,
+  ObjectTypeInformation,
+  ObjectAllInformation,
+  ObjectDataInformation
+} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
+
+typedef struct _OBJDIR_INFORMATION {
+  UNICODE_STRING ObjectName;
+  UNICODE_STRING ObjectTypeName;
+  BYTE Data[1];
+} OBJDIR_INFORMATION;
+
+typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
+  ULONG Attributes;
+  ACCESS_MASK GrantedAccess;
+  ULONG HandleCount;
+  ULONG PointerCount;
+  ULONG Reserved[10];    // reserved for internal use
+} PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION;
+
+typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING TypeName;
+  ULONG Reserved[22];    // reserved for internal use
+} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;
+
+typedef enum _POOL_TYPE {
+  NonPagedPool,
+  PagedPool,
+  NonPagedPoolMustSucceed,
+  ReservedType,
+  NonPagedPoolCacheAligned,
+  PagedPoolCacheAligned,
+  NonPagedPoolCacheAlignedMustS
+} POOL_TYPE;
+
+typedef struct _OBJECT_BASIC_INFORMATION {
+  ULONG Attributes;
+  ACCESS_MASK GrantedAccess;
+  ULONG HandleCount;
+  ULONG PointerCount;
+  ULONG PagedPoolUsage;
+  ULONG NonPagedPoolUsage;
+  ULONG Reserved[3];
+  ULONG NameInformationLength;
+  ULONG TypeInformationLength;
+  ULONG SecurityDescriptorLength;
+  LARGE_INTEGER CreateTime;
+} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
+
+typedef struct _OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING Name;
+  ULONG TotalNumberOfObjects;
+  ULONG TotalNumberOfHandles;
+  ULONG TotalPagedPoolUsage;
+  ULONG TotalNonPagedPoolUsage;
+  ULONG TotalNamePoolUsage;
+  ULONG TotalHandleTableUsage;
+  ULONG HighWaterNumberOfObjects;
+  ULONG HighWaterNumberOfHandles;
+  ULONG HighWaterPagedPoolUsage;
+  ULONG HighWaterNonPagedPoolUsage;
+  ULONG HighWaterNamePoolUsage;
+  ULONG HighWaterHandleTableUsage;
+  ULONG InvalidAttributes;
+  GENERIC_MAPPING GenericMapping;
+  ULONG ValidAccess;
+  BOOLEAN SecurityRequired;
+  BOOLEAN MaintainHandleCount;
+  USHORT MaintainTypeList;
+  POOL_TYPE PoolType;
+  ULONG PagedPoolUsage;
+  ULONG NonPagedPoolUsage;
+} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+  SystemHandleInformation = 16
+} SYSTEM_INFORMATION_CLASS;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION {
+  USHORT ProcessId;
+  USHORT CreatorBackTraceIndex;
+  UCHAR ObjectTypeNumber;
+  UCHAR Flags;
+  USHORT Handle;
+  PVOID Object;
+  ACCESS_MASK GrantedAccess;
+} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+  ULONG NumberOfHandles;
+  SYSTEM_HANDLE_INFORMATION Information[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
+typedef struct _OBJECT_NAME_INFORMATION {
+  UNICODE_STRING ObjectName;
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef NTSTATUS (WINAPI *NtQueryObjectFunction)(
+  IN HANDLE Handle,
+  IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
+  OUT PVOID ObjectInformation OPTIONAL,
+  IN ULONG ObjectInformationLength,
+  OUT PULONG ReturnLength OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtDuplicateObjectFunction)(
+  IN HANDLE SourceProcess,
+  IN HANDLE SourceHandle,
+  IN HANDLE TargetProcess,
+  OUT PHANDLE TargetHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN ULONG Attributes,
+  IN ULONG Options);
+
+typedef NTSTATUS (WINAPI *NtSignalAndWaitForSingleObjectFunction)(
+  IN HANDLE HandleToSignal,
+  IN HANDLE HandleToWait,
+  IN BOOLEAN Alertable,
+  IN PLARGE_INTEGER Timeout OPTIONAL);
+
+typedef NTSTATUS (WINAPI *NtQuerySystemInformation)(
+  IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
+  OUT PVOID SystemInformation,
+  IN ULONG SystemInformationLength,
+  OUT PULONG ReturnLength);
+
+typedef NTSTATUS (WINAPI *NtQueryObject)(
+  IN HANDLE Handle,
+  IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
+  OUT PVOID ObjectInformation,
+  IN ULONG ObjectInformationLength,
+  OUT PULONG ReturnLength);
+
+// -----------------------------------------------------------------------
+// Strings
+
+typedef int (__cdecl *_strnicmpFunction)(
+  IN const char* _Str1,
+  IN const char* _Str2,
+  IN size_t _MaxCount);
+
+typedef size_t  (__cdecl *strlenFunction)(
+  IN const char * _Str);
+
+typedef size_t (__cdecl *wcslenFunction)(
+  IN const wchar_t* _Str);
+
+typedef void* (__cdecl *memcpyFunction)(
+  IN void* dest,
+  IN const void* src,
+  IN size_t count);
+
+typedef NTSTATUS (WINAPI *RtlAnsiStringToUnicodeStringFunction)(
+  IN OUT PUNICODE_STRING  DestinationString,
+  IN PANSI_STRING  SourceString,
+  IN BOOLEAN  AllocateDestinationString);
+
+typedef LONG (WINAPI *RtlCompareUnicodeStringFunction)(
+  IN PCUNICODE_STRING  String1,
+  IN PCUNICODE_STRING  String2,
+  IN BOOLEAN  CaseInSensitive);
+
+typedef VOID (WINAPI *RtlInitUnicodeStringFunction) (
+  IN OUT PUNICODE_STRING DestinationString,
+  IN PCWSTR SourceString);
+
+typedef ULONG (WINAPI* RtlNtStatusToDosErrorFunction)(NTSTATUS status);
+
+typedef enum _EVENT_TYPE {
+  NotificationEvent,
+  SynchronizationEvent
+} EVENT_TYPE, *PEVENT_TYPE;
+
+typedef NTSTATUS (WINAPI* NtCreateDirectoryObjectFunction) (
+    PHANDLE DirectoryHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NtOpenDirectoryObjectFunction) (
+    PHANDLE DirectoryHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NtQuerySymbolicLinkObjectFunction) (
+    HANDLE LinkHandle,
+    PUNICODE_STRING LinkTarget,
+    PULONG ReturnedLength);
+
+typedef NTSTATUS (WINAPI* NtOpenSymbolicLinkObjectFunction) (
+    PHANDLE LinkHandle,
+    ACCESS_MASK DesiredAccess,
+    POBJECT_ATTRIBUTES ObjectAttributes);
+
+#define DIRECTORY_QUERY               0x0001
+#define DIRECTORY_TRAVERSE            0x0002
+#define DIRECTORY_CREATE_OBJECT       0x0004
+#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
+#define DIRECTORY_ALL_ACCESS          0x000F
+
+typedef NTSTATUS (WINAPI* NtCreateLowBoxToken)(
+    OUT PHANDLE token,
+    IN HANDLE original_handle,
+    IN ACCESS_MASK access,
+    IN POBJECT_ATTRIBUTES object_attribute,
+    IN PSID appcontainer_sid,
+    IN DWORD capabilityCount,
+    IN PSID_AND_ATTRIBUTES capabilities,
+    IN DWORD handle_count,
+    IN PHANDLE handles);
+
+typedef NTSTATUS(WINAPI *NtSetInformationProcess)(
+    IN HANDLE process_handle,
+    IN ULONG info_class,
+    IN PVOID process_information,
+    IN ULONG information_length);
+
+struct PROCESS_ACCESS_TOKEN {
+  HANDLE token;
+  HANDLE thread;
+};
+
+const unsigned int NtProcessInformationAccessToken = 9;
+
+// -----------------------------------------------------------------------
+// GDI OPM API and Supported Calls
+
+#define DXGKMDT_OPM_OMAC_SIZE 16
+#define DXGKMDT_OPM_128_BIT_RANDOM_NUMBER_SIZE 16
+#define DXGKMDT_OPM_ENCRYPTED_PARAMETERS_SIZE 256
+#define DXGKMDT_OPM_CONFIGURE_SETTING_DATA_SIZE 4056
+#define DXGKMDT_OPM_GET_INFORMATION_PARAMETERS_SIZE 4056
+#define DXGKMDT_OPM_REQUESTED_INFORMATION_SIZE 4076
+#define DXGKMDT_OPM_HDCP_KEY_SELECTION_VECTOR_SIZE 5
+#define DXGKMDT_OPM_PROTECTION_TYPE_SIZE 4
+
+enum DXGKMDT_CERTIFICATE_TYPE {
+  DXGKMDT_OPM_CERTIFICATE = 0,
+  DXGKMDT_COPP_CERTIFICATE = 1,
+  DXGKMDT_UAB_CERTIFICATE = 2,
+  DXGKMDT_FORCE_ULONG = 0xFFFFFFFF
+};
+
+enum DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS {
+  DXGKMDT_OPM_VOS_COPP_SEMANTICS = 0,
+  DXGKMDT_OPM_VOS_OPM_SEMANTICS = 1
+};
+
+enum DXGKMDT_DPCP_PROTECTION_LEVEL {
+  DXGKMDT_OPM_DPCP_OFF = 0,
+  DXGKMDT_OPM_DPCP_ON = 1,
+  DXGKMDT_OPM_DPCP_FORCE_ULONG = 0x7fffffff
+};
+
+enum DXGKMDT_OPM_HDCP_PROTECTION_LEVEL {
+  DXGKMDT_OPM_HDCP_OFF = 0,
+  DXGKMDT_OPM_HDCP_ON = 1,
+  DXGKMDT_OPM_HDCP_FORCE_ULONG = 0x7fffffff
+};
+
+enum DXGKMDT_OPM_HDCP_FLAG {
+  DXGKMDT_OPM_HDCP_FLAG_NONE = 0x00,
+  DXGKMDT_OPM_HDCP_FLAG_REPEATER = 0x01
+};
+
+enum DXGKMDT_OPM_PROTECTION_TYPE {
+  DXGKMDT_OPM_PROTECTION_TYPE_OTHER = 0x80000000,
+  DXGKMDT_OPM_PROTECTION_TYPE_NONE = 0x00000000,
+  DXGKMDT_OPM_PROTECTION_TYPE_COPP_COMPATIBLE_HDCP = 0x00000001,
+  DXGKMDT_OPM_PROTECTION_TYPE_ACP = 0x00000002,
+  DXGKMDT_OPM_PROTECTION_TYPE_CGMSA = 0x00000004,
+  DXGKMDT_OPM_PROTECTION_TYPE_HDCP = 0x00000008,
+  DXGKMDT_OPM_PROTECTION_TYPE_DPCP = 0x00000010,
+  DXGKMDT_OPM_PROTECTION_TYPE_MASK = 0x8000001F
+};
+
+typedef void* OPM_PROTECTED_OUTPUT_HANDLE;
+
+struct DXGKMDT_OPM_ENCRYPTED_PARAMETERS {
+  BYTE abEncryptedParameters[DXGKMDT_OPM_ENCRYPTED_PARAMETERS_SIZE];
+};
+
+struct DXGKMDT_OPM_OMAC {
+  BYTE abOMAC[DXGKMDT_OPM_OMAC_SIZE];
+};
+
+struct DXGKMDT_OPM_CONFIGURE_PARAMETERS {
+  DXGKMDT_OPM_OMAC omac;
+  GUID guidSetting;
+  ULONG ulSequenceNumber;
+  ULONG cbParametersSize;
+  BYTE abParameters[DXGKMDT_OPM_CONFIGURE_SETTING_DATA_SIZE];
+};
+
+struct DXGKMDT_OPM_RANDOM_NUMBER {
+  BYTE abRandomNumber[DXGKMDT_OPM_128_BIT_RANDOM_NUMBER_SIZE];
+};
+
+struct DXGKMDT_OPM_GET_INFO_PARAMETERS {
+  DXGKMDT_OPM_OMAC omac;
+  DXGKMDT_OPM_RANDOM_NUMBER rnRandomNumber;
+  GUID guidInformation;
+  ULONG ulSequenceNumber;
+  ULONG cbParametersSize;
+  BYTE abParameters[DXGKMDT_OPM_GET_INFORMATION_PARAMETERS_SIZE];
+};
+
+struct DXGKMDT_OPM_REQUESTED_INFORMATION {
+  DXGKMDT_OPM_OMAC omac;
+  ULONG cbRequestedInformationSize;
+  BYTE abRequestedInformation[DXGKMDT_OPM_REQUESTED_INFORMATION_SIZE];
+};
+
+struct DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS {
+  ULONG ulProtectionType;
+  ULONG ulProtectionLevel;
+  ULONG Reserved;
+  ULONG Reserved2;
+};
+
+struct DXGKMDT_OPM_STANDARD_INFORMATION {
+  DXGKMDT_OPM_RANDOM_NUMBER rnRandomNumber;
+  ULONG ulStatusFlags;
+  ULONG ulInformation;
+  ULONG ulReserved;
+  ULONG ulReserved2;
+};
+
+typedef NTSTATUS(WINAPI* GetSuggestedOPMProtectedOutputArraySizeFunction)(
+    PUNICODE_STRING device_name,
+    DWORD* suggested_output_array_size);
+
+typedef NTSTATUS(WINAPI* CreateOPMProtectedOutputsFunction)(
+    PUNICODE_STRING device_name,
+    DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
+    DWORD output_array_size,
+    DWORD* num_in_output_array,
+    OPM_PROTECTED_OUTPUT_HANDLE* output_array);
+
+typedef NTSTATUS(WINAPI* GetCertificateFunction)(
+    PUNICODE_STRING device_name,
+    DXGKMDT_CERTIFICATE_TYPE certificate_type,
+    BYTE* certificate,
+    ULONG certificate_length);
+
+typedef NTSTATUS(WINAPI* GetCertificateSizeFunction)(
+    PUNICODE_STRING device_name,
+    DXGKMDT_CERTIFICATE_TYPE certificate_type,
+    ULONG* certificate_length);
+
+typedef NTSTATUS(WINAPI* GetCertificateByHandleFunction)(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    DXGKMDT_CERTIFICATE_TYPE certificate_type,
+    BYTE* certificate,
+    ULONG certificate_length);
+
+typedef NTSTATUS(WINAPI* GetCertificateSizeByHandleFunction)(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    DXGKMDT_CERTIFICATE_TYPE certificate_type,
+    ULONG* certificate_length);
+
+typedef NTSTATUS(WINAPI* DestroyOPMProtectedOutputFunction)(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output);
+
+typedef NTSTATUS(WINAPI* ConfigureOPMProtectedOutputFunction)(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
+    ULONG additional_parameters_size,
+    const BYTE* additional_parameters);
+
+typedef NTSTATUS(WINAPI* GetOPMInformationFunction)(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
+    DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information);
+
+typedef NTSTATUS(WINAPI* GetOPMRandomNumberFunction)(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    DXGKMDT_OPM_RANDOM_NUMBER* random_number);
+
+typedef NTSTATUS(WINAPI* SetOPMSigningKeyAndSequenceNumbersFunction)(
+    OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+    const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters);
+
+#endif  // SANDBOX_WIN_SRC_NT_INTERNALS_H__
+
diff --git a/libchrome/sandbox/win/src/policy_engine_params.h b/libchrome/sandbox/win/src/policy_engine_params.h
new file mode 100644
index 0000000..fb4c00e
--- /dev/null
+++ b/libchrome/sandbox/win/src/policy_engine_params.h
@@ -0,0 +1,202 @@
+// 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 SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
+#define SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
+
+#include <stdint.h>
+
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+// This header defines the classes that allow the low level policy to select
+// the input parameters. In order to better make sense of this header is
+// recommended that you check policy_engine_opcodes.h first.
+
+namespace sandbox {
+
+// Models the set of interesting parameters of an intercepted system call
+// normally you don't create objects of this class directly, instead you
+// use the POLPARAMS_XXX macros.
+// For example, if an intercepted function has the following signature:
+//
+// NTSTATUS NtOpenFileFunction (PHANDLE FileHandle,
+//                              ACCESS_MASK DesiredAccess,
+//                              POBJECT_ATTRIBUTES ObjectAttributes,
+//                              PIO_STATUS_BLOCK IoStatusBlock,
+//                              ULONG ShareAccess,
+//                              ULONG OpenOptions);
+//
+// You could say that the following parameters are of interest to policy:
+//
+//   POLPARAMS_BEGIN(open_params)
+//      POLPARAM(DESIRED_ACCESS)
+//      POLPARAM(OBJECT_NAME)
+//      POLPARAM(SECURITY_DESCRIPTOR)
+//      POLPARAM(IO_STATUS)
+//      POLPARAM(OPEN_OPTIONS)
+//   POLPARAMS_END;
+//
+// and the actual code will use this for defining the parameters:
+//
+//   CountedParameterSet<open_params> p;
+//   p[open_params::DESIRED_ACCESS] = ParamPickerMake(DesiredAccess);
+//   p[open_params::OBJECT_NAME] =
+//       ParamPickerMake(ObjectAttributes->ObjectName);
+//   p[open_params::SECURITY_DESCRIPTOR] =
+//       ParamPickerMake(ObjectAttributes->SecurityDescriptor);
+//   p[open_params::IO_STATUS] = ParamPickerMake(IoStatusBlock);
+//   p[open_params::OPEN_OPTIONS] = ParamPickerMake(OpenOptions);
+//
+//  These will create an stack-allocated array of ParameterSet objects which
+//  have each 1) the address of the parameter 2) a numeric id that encodes the
+//  original C++ type. This allows the policy to treat any set of supported
+//  argument types uniformily and with some type safety.
+//
+//  TODO(cpu): support not fully implemented yet for unicode string and will
+//  probably add other types as well.
+class ParameterSet {
+ public:
+  ParameterSet() : real_type_(INVALID_TYPE), address_(NULL) {}
+
+  // Retrieve the stored parameter. If the type does not match ulong fail.
+  bool Get(uint32_t* destination) const {
+    if (real_type_ != UINT32_TYPE) {
+      return false;
+    }
+    *destination = Void2TypePointerCopy<uint32_t>();
+    return true;
+  }
+
+  // Retrieve the stored parameter. If the type does not match void* fail.
+  bool Get(const void** destination) const {
+    if (real_type_ != VOIDPTR_TYPE) {
+      return false;
+    }
+    *destination = Void2TypePointerCopy<void*>();
+    return true;
+  }
+
+  // Retrieve the stored parameter. If the type does not match wchar_t* fail.
+  bool Get(const wchar_t** destination) const {
+    if (real_type_ != WCHAR_TYPE) {
+      return false;
+    }
+    *destination = Void2TypePointerCopy<const wchar_t*>();
+    return true;
+  }
+
+  // False if the parameter is not properly initialized.
+  bool IsValid() const {
+    return real_type_ != INVALID_TYPE;
+  }
+
+ protected:
+  // The constructor can only be called by derived types, which should
+  // safely provide the real_type and the address of the argument.
+  ParameterSet(ArgType real_type, const void* address)
+      : real_type_(real_type), address_(address) {
+  }
+
+ private:
+  // This template provides the same functionality as bits_cast but
+  // it works with pointer while the former works only with references.
+  template <typename T>
+  T Void2TypePointerCopy() const {
+    return *(reinterpret_cast<const T*>(address_));
+  }
+
+  ArgType real_type_;
+  const void* address_;
+};
+
+// To safely infer the type, we use a set of template specializations
+// in ParameterSetEx with a template function ParamPickerMake to do the
+// parameter type deduction.
+
+// Base template class. Not implemented so using unsupported types should
+// fail to compile.
+template <typename T>
+class ParameterSetEx : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address);
+};
+
+template<>
+class ParameterSetEx<void const*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(VOIDPTR_TYPE, address) {}
+};
+
+template<>
+class ParameterSetEx<void*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(VOIDPTR_TYPE, address) {}
+};
+
+
+template<>
+class ParameterSetEx<wchar_t*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(WCHAR_TYPE, address) {}
+};
+
+template<>
+class ParameterSetEx<wchar_t const*> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(WCHAR_TYPE, address) {}
+};
+
+template <>
+class ParameterSetEx<uint32_t> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(UINT32_TYPE, address) {}
+};
+
+template<>
+class ParameterSetEx<UNICODE_STRING> : public ParameterSet {
+ public:
+  ParameterSetEx(const void* address)
+      : ParameterSet(UNISTR_TYPE, address) {}
+};
+
+template <typename T>
+ParameterSet ParamPickerMake(T& parameter) {
+  return ParameterSetEx<T>(&parameter);
+};
+
+struct CountedParameterSetBase {
+  int count;
+  ParameterSet parameters[1];
+};
+
+// This template defines the actual list of policy parameters for a given
+// interception.
+// Warning: This template stores the address to the actual variables, in
+// other words, the values are not copied.
+template <typename T>
+struct CountedParameterSet {
+  CountedParameterSet() : count(T::PolParamLast) {}
+
+  ParameterSet& operator[](typename T::Args n) {
+    return parameters[n];
+  }
+
+  CountedParameterSetBase* GetBase() {
+    return reinterpret_cast<CountedParameterSetBase*>(this);
+  }
+
+  int count;
+  ParameterSet parameters[T::PolParamLast];
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
diff --git a/libchrome/sandbox/win/src/policy_params.h b/libchrome/sandbox/win/src/policy_params.h
new file mode 100644
index 0000000..e051d2b
--- /dev/null
+++ b/libchrome/sandbox/win/src/policy_params.h
@@ -0,0 +1,67 @@
+// 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 SANDBOX_SRC_POLICY_PARAMS_H__
+#define SANDBOX_SRC_POLICY_PARAMS_H__
+
+#include "sandbox/win/src/policy_engine_params.h"
+
+namespace sandbox {
+
+class ParameterSet;
+
+// Warning: The following macros store the address to the actual variables, in
+// other words, the values are not copied.
+#define POLPARAMS_BEGIN(type) class type { public: enum Args {
+#define POLPARAM(arg) arg,
+#define POLPARAMS_END(type) PolParamLast }; }; \
+  typedef sandbox::ParameterSet type##Array [type::PolParamLast];
+
+// Policy parameters for file open / create.
+POLPARAMS_BEGIN(OpenFile)
+  POLPARAM(NAME)
+  POLPARAM(BROKER)   // TRUE if called from the broker.
+  POLPARAM(ACCESS)
+  POLPARAM(DISPOSITION)
+  POLPARAM(OPTIONS)
+POLPARAMS_END(OpenFile)
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(FileName)
+  POLPARAM(NAME)
+  POLPARAM(BROKER)   // TRUE if called from the broker.
+POLPARAMS_END(FileName)
+
+static_assert(OpenFile::NAME == static_cast<int>(FileName::NAME),
+              "to simplify fs policies");
+static_assert(OpenFile::BROKER == static_cast<int>(FileName::BROKER),
+              "to simplify fs policies");
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(NameBased)
+  POLPARAM(NAME)
+POLPARAMS_END(NameBased)
+
+// Policy parameters for open event.
+POLPARAMS_BEGIN(OpenEventParams)
+  POLPARAM(NAME)
+  POLPARAM(ACCESS)
+POLPARAMS_END(OpenEventParams)
+
+// Policy Parameters for reg open / create.
+POLPARAMS_BEGIN(OpenKey)
+  POLPARAM(NAME)
+  POLPARAM(ACCESS)
+POLPARAMS_END(OpenKey)
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(HandleTarget)
+  POLPARAM(NAME)
+  POLPARAM(TARGET)
+POLPARAMS_END(HandleTarget)
+
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_POLICY_PARAMS_H__
diff --git a/libchrome/sandbox/win/src/sandbox.vcproj b/libchrome/sandbox/win/src/sandbox.vcproj
new file mode 100644
index 0000000..f206e01
--- /dev/null
+++ b/libchrome/sandbox/win/src/sandbox.vcproj
@@ -0,0 +1,658 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sandbox"
+	ProjectGUID="{881F6A97-D539-4C48-B401-DF04385B2343}"
+	RootNamespace="sandbox"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				Description="Copy wow_helper to output directory"
+				CommandLine="copy $(ProjectDir)\..\wow_helper\wow_helper.exe $(OutDir) &amp;&amp; copy $(ProjectDir)\..\wow_helper\wow_helper.pdb $(OutDir)"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				Description="Copy wow_helper to output directory"
+				CommandLine="copy $(ProjectDir)\..\wow_helper\wow_helper.exe $(OutDir) &amp;&amp; copy $(ProjectDir)\..\wow_helper\wow_helper.pdb $(OutDir)"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="security"
+			>
+			<File
+				RelativePath=".\acl.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\acl.h"
+				>
+			</File>
+			<File
+				RelativePath=".\dep.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\dep.h"
+				>
+			</File>
+			<File
+				RelativePath=".\job.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\job.h"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token.h"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token_utils.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\restricted_token_utils.h"
+				>
+			</File>
+			<File
+				RelativePath=".\security_level.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sid.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sid.h"
+				>
+			</File>
+			<File
+				RelativePath=".\window.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\window.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Interception"
+			>
+			<File
+				RelativePath=".\eat_resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\eat_resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\interception_agent.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\interception_agent.h"
+				>
+			</File>
+			<File
+				RelativePath=".\interception_internal.h"
+				>
+			</File>
+			<File
+				RelativePath=".\pe_image.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\pe_image.h"
+				>
+			</File>
+			<File
+				RelativePath=".\resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\service_resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\service_resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sidestep_resolver.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sidestep_resolver.h"
+				>
+			</File>
+			<File
+				RelativePath=".\target_interceptions.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\target_interceptions.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Wow64.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\Wow64.h"
+				>
+			</File>
+			<Filter
+				Name="sidestep"
+				>
+				<File
+					RelativePath=".\sidestep\ia32_modrm_map.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\ia32_opcode_map.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\mini_disassembler.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\mini_disassembler.h"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\mini_disassembler_types.h"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\preamble_patcher.h"
+					>
+				</File>
+				<File
+					RelativePath=".\sidestep\preamble_patcher_with_stub.cpp"
+					>
+				</File>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="nt_level"
+			>
+			<File
+				RelativePath=".\nt_internals.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_target.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_target.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_nt_types.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_nt_util.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_nt_util.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Policy_handlers"
+			>
+			<File
+				RelativePath=".\filesystem_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\filesystem_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\named_pipe_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_params.h"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\process_thread_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\registry_policy.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_dispatcher.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_dispatcher.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_interception.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_interception.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_policy.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sync_policy.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="IPC"
+			>
+			<File
+				RelativePath=".\crosscall_client.h"
+				>
+			</File>
+			<File
+				RelativePath=".\crosscall_params.h"
+				>
+			</File>
+			<File
+				RelativePath=".\crosscall_server.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\crosscall_server.h"
+				>
+			</File>
+			<File
+				RelativePath=".\ipc_tags.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_client.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_client.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_server.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sharedmem_ipc_server.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Policy_base"
+			>
+			<File
+				RelativePath=".\policy_engine_opcodes.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_opcodes.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_params.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_processor.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_engine_processor.h"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_low_level.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\policy_low_level.h"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_policy_base.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\sandbox_policy_base.h"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath=".\broker_services.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\broker_services.h"
+			>
+		</File>
+		<File
+			RelativePath=".\internal_types.h"
+			>
+		</File>
+		<File
+			RelativePath=".\policy_broker.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\policy_broker.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_factory.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_policy.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_types.h"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_utils.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\sandbox_utils.h"
+			>
+		</File>
+		<File
+			RelativePath=".\shared_handles.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\shared_handles.h"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+		<File
+			RelativePath=".\target_process.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\target_process.h"
+			>
+		</File>
+		<File
+			RelativePath=".\target_services.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\target_services.h"
+			>
+		</File>
+		<File
+			RelativePath=".\win2k_threadpool.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\win2k_threadpool.h"
+			>
+		</File>
+		<File
+			RelativePath=".\win_utils.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\win_utils.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/src/sandbox_factory.h b/libchrome/sandbox/win/src/sandbox_factory.h
new file mode 100644
index 0000000..f5888ff
--- /dev/null
+++ b/libchrome/sandbox/win/src/sandbox_factory.h
@@ -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.
+
+#ifndef SANDBOX_SRC_SANDBOX_FACTORY_H__
+#define SANDBOX_SRC_SANDBOX_FACTORY_H__
+
+#include "base/macros.h"
+#include "sandbox/win/src/sandbox.h"
+
+// SandboxFactory is a set of static methods to get access to the broker
+// or target services object. Only one of the two methods (GetBrokerServices,
+// GetTargetServices) will return a non-null pointer and that should be used
+// as the indication that the process is the broker or the target:
+//
+// BrokerServices* broker_services = SandboxFactory::GetBrokerServices();
+// if (NULL != broker_services) {
+//   //we are the broker, call broker api here
+//   broker_services->Init();
+// } else {
+//   TargetServices* target_services = SandboxFactory::GetTargetServices();
+//   if (NULL != target_services) {
+//    //we are the target, call target api here
+//    target_services->Init();
+//  }
+//
+// The methods in this class are expected to be called from a single thread
+//
+// The Sandbox library needs to be linked against the main executable, but
+// sometimes the API calls are issued from a DLL that loads into the exe
+// process. These factory methods then need to be called from the main
+// exe and the interface pointers then can be safely passed to the DLL where
+// the Sandbox API calls are made.
+namespace sandbox {
+
+class SandboxFactory {
+ public:
+  // Returns the Broker API interface, returns NULL if this process is the
+  // target.
+  static BrokerServices* GetBrokerServices();
+
+  // Returns the Target API interface, returns NULL if this process is the
+  // broker.
+  static TargetServices* GetTargetServices();
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SandboxFactory);
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SANDBOX_FACTORY_H__
diff --git a/libchrome/sandbox/win/src/sandbox_nt_types.h b/libchrome/sandbox/win/src/sandbox_nt_types.h
new file mode 100644
index 0000000..a4a88bb
--- /dev/null
+++ b/libchrome/sandbox/win/src/sandbox_nt_types.h
@@ -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.
+
+#ifndef SANDBOX_SRC_SANDBOX_NT_TYPES_H__
+#define SANDBOX_SRC_SANDBOX_NT_TYPES_H__
+
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+struct NtExports {
+  NtAllocateVirtualMemoryFunction       AllocateVirtualMemory;
+  NtCloseFunction                       Close;
+  NtDuplicateObjectFunction             DuplicateObject;
+  NtFreeVirtualMemoryFunction           FreeVirtualMemory;
+  NtMapViewOfSectionFunction            MapViewOfSection;
+  NtProtectVirtualMemoryFunction        ProtectVirtualMemory;
+  NtQueryInformationProcessFunction     QueryInformationProcess;
+  NtQueryObjectFunction                 QueryObject;
+  NtQuerySectionFunction                QuerySection;
+  NtQueryVirtualMemoryFunction          QueryVirtualMemory;
+  NtUnmapViewOfSectionFunction          UnmapViewOfSection;
+  RtlAllocateHeapFunction               RtlAllocateHeap;
+  RtlAnsiStringToUnicodeStringFunction  RtlAnsiStringToUnicodeString;
+  RtlCompareUnicodeStringFunction       RtlCompareUnicodeString;
+  RtlCreateHeapFunction                 RtlCreateHeap;
+  RtlCreateUserThreadFunction           RtlCreateUserThread;
+  RtlDestroyHeapFunction                RtlDestroyHeap;
+  RtlFreeHeapFunction                   RtlFreeHeap;
+  _strnicmpFunction                     _strnicmp;
+  strlenFunction                        strlen;
+  wcslenFunction                        wcslen;
+  memcpyFunction                        memcpy;
+};
+
+// This is the value used for the ntdll level allocator.
+enum AllocationType {
+  NT_ALLOC,
+  NT_PAGE
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_SRC_SANDBOX_NT_TYPES_H__
diff --git a/libchrome/sandbox/win/src/sandbox_policy.h b/libchrome/sandbox/win/src/sandbox_policy.h
new file mode 100644
index 0000000..c0916ea
--- /dev/null
+++ b/libchrome/sandbox/win/src/sandbox_policy.h
@@ -0,0 +1,260 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/strings/string16.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/security_level.h"
+
+namespace sandbox {
+
+class TargetPolicy {
+ public:
+  // Windows subsystems that can have specific rules.
+  // Note: The process subsystem(SUBSY_PROCESS) does not evaluate the request
+  // exactly like the CreateProcess API does. See the comment at the top of
+  // process_thread_dispatcher.cc for more details.
+  enum SubSystem {
+    SUBSYS_FILES,             // Creation and opening of files and pipes.
+    SUBSYS_NAMED_PIPES,       // Creation of named pipes.
+    SUBSYS_PROCESS,           // Creation of child processes.
+    SUBSYS_REGISTRY,          // Creation and opening of registry keys.
+    SUBSYS_SYNC,              // Creation of named sync objects.
+    SUBSYS_WIN32K_LOCKDOWN    // Win32K Lockdown related policy.
+  };
+
+  // Allowable semantics when a rule is matched.
+  enum Semantics {
+    FILES_ALLOW_ANY,       // Allows open or create for any kind of access that
+                           // the file system supports.
+    FILES_ALLOW_READONLY,  // Allows open or create with read access only.
+    FILES_ALLOW_QUERY,     // Allows access to query the attributes of a file.
+    FILES_ALLOW_DIR_ANY,   // Allows open or create with directory semantics
+                           // only.
+    NAMEDPIPES_ALLOW_ANY,  // Allows creation of a named pipe.
+    PROCESS_MIN_EXEC,      // Allows to create a process with minimal rights
+                           // over the resulting process and thread handles.
+                           // No other parameters besides the command line are
+                           // passed to the child process.
+    PROCESS_ALL_EXEC,      // Allows the creation of a process and return full
+                           // access on the returned handles.
+                           // This flag can be used only when the main token of
+                           // the sandboxed application is at least INTERACTIVE.
+    EVENTS_ALLOW_ANY,      // Allows the creation of an event with full access.
+    EVENTS_ALLOW_READONLY,  // Allows opening an even with synchronize access.
+    REG_ALLOW_READONLY,     // Allows readonly access to a registry key.
+    REG_ALLOW_ANY,          // Allows read and write access to a registry key.
+    FAKE_USER_GDI_INIT,     // Fakes user32 and gdi32 initialization. This can
+                            // be used to allow the DLLs to load and initialize
+                            // even if the process cannot access that subsystem.
+    IMPLEMENT_OPM_APIS      // Implements FAKE_USER_GDI_INIT and also exposes
+                            // IPC calls to handle Output Protection Manager
+                            // APIs.
+  };
+
+  // Increments the reference count of this object. The reference count must
+  // be incremented if this interface is given to another component.
+  virtual void AddRef() = 0;
+
+  // Decrements the reference count of this object. When the reference count
+  // is zero the object is automatically destroyed.
+  // Indicates that the caller is done with this interface. After calling
+  // release no other method should be called.
+  virtual void Release() = 0;
+
+  // Sets the security level for the target process' two tokens.
+  // This setting is permanent and cannot be changed once the target process is
+  // spawned.
+  // initial: the security level for the initial token. This is the token that
+  //   is used by the process from the creation of the process until the moment
+  //   the process calls TargetServices::LowerToken() or the process calls
+  //   win32's RevertToSelf(). Once this happens the initial token is no longer
+  //   available and the lockdown token is in effect. Using an initial token is
+  //   not compatible with AppContainer, see SetAppContainer.
+  // lockdown: the security level for the token that comes into force after the
+  //   process calls TargetServices::LowerToken() or the process calls
+  //   RevertToSelf(). See the explanation of each level in the TokenLevel
+  //   definition.
+  // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
+  //   Returns false if the lockdown value is more permissive than the initial
+  //   value.
+  //
+  // Important: most of the sandbox-provided security relies on this single
+  // setting. The caller should strive to set the lockdown level as restricted
+  // as possible.
+  virtual ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) = 0;
+
+  // Returns the initial token level.
+  virtual TokenLevel GetInitialTokenLevel() const = 0;
+
+  // Returns the lockdown token level.
+  virtual TokenLevel GetLockdownTokenLevel() const = 0;
+
+  // Sets the security level of the Job Object to which the target process will
+  // belong. This setting is permanent and cannot be changed once the target
+  // process is spawned. The job controls the global security settings which
+  // can not be specified in the token security profile.
+  // job_level: the security level for the job. See the explanation of each
+  //   level in the JobLevel definition.
+  // ui_exceptions: specify what specific rights that are disabled in the
+  //   chosen job_level that need to be granted. Use this parameter to avoid
+  //   selecting the next permissive job level unless you need all the rights
+  //   that are granted in such level.
+  //   The exceptions can be specified as a combination of the following
+  //   constants:
+  // JOB_OBJECT_UILIMIT_HANDLES : grant access to all user-mode handles. These
+  //   include windows, icons, menus and various GDI objects. In addition the
+  //   target process can set hooks, and broadcast messages to other processes
+  //   that belong to the same desktop.
+  // JOB_OBJECT_UILIMIT_READCLIPBOARD : grant read-only access to the clipboard.
+  // JOB_OBJECT_UILIMIT_WRITECLIPBOARD : grant write access to the clipboard.
+  // JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS : allow changes to the system-wide
+  //   parameters as defined by the Win32 call SystemParametersInfo().
+  // JOB_OBJECT_UILIMIT_DISPLAYSETTINGS : allow programmatic changes to the
+  //  display settings.
+  // JOB_OBJECT_UILIMIT_GLOBALATOMS : allow access to the global atoms table.
+  // JOB_OBJECT_UILIMIT_DESKTOP : allow the creation of new desktops.
+  // JOB_OBJECT_UILIMIT_EXITWINDOWS : allow the call to ExitWindows().
+  //
+  // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
+  //
+  // Note: JOB_OBJECT_XXXX constants are defined in winnt.h and documented at
+  // length in:
+  //   http://msdn2.microsoft.com/en-us/library/ms684152.aspx
+  //
+  // Note: the recommended level is JOB_RESTRICTED or JOB_LOCKDOWN.
+  virtual ResultCode SetJobLevel(JobLevel job_level,
+                                 uint32_t ui_exceptions) = 0;
+
+  // Returns the job level.
+  virtual JobLevel GetJobLevel() const = 0;
+
+  // Sets a hard limit on the size of the commit set for the sandboxed process.
+  // If the limit is reached, the process will be terminated with
+  // SBOX_FATAL_MEMORY_EXCEEDED (7012).
+  virtual ResultCode SetJobMemoryLimit(size_t memory_limit) = 0;
+
+  // Specifies the desktop on which the application is going to run. If the
+  // desktop does not exist, it will be created. If alternate_winstation is
+  // set to true, the desktop will be created on an alternate window station.
+  virtual ResultCode SetAlternateDesktop(bool alternate_winstation) = 0;
+
+  // Returns the name of the alternate desktop used. If an alternate window
+  // station is specified, the name is prepended by the window station name,
+  // followed by a backslash.
+  virtual base::string16 GetAlternateDesktop() const = 0;
+
+  // Precreates the desktop and window station, if any.
+  virtual ResultCode CreateAlternateDesktop(bool alternate_winstation) = 0;
+
+  // Destroys the desktop and windows station.
+  virtual void DestroyAlternateDesktop() = 0;
+
+  // Sets the integrity level of the process in the sandbox. Both the initial
+  // token and the main token will be affected by this. If the integrity level
+  // is set to a level higher than the current level, the sandbox will fail
+  // to start.
+  virtual ResultCode SetIntegrityLevel(IntegrityLevel level) = 0;
+
+  // Returns the initial integrity level used.
+  virtual IntegrityLevel GetIntegrityLevel() const = 0;
+
+  // Sets the integrity level of the process in the sandbox. The integrity level
+  // will not take effect before you call LowerToken. User Interface Privilege
+  // Isolation is not affected by this setting and will remain off for the
+  // process in the sandbox. If the integrity level is set to a level higher
+  // than the current level, the sandbox will fail to start.
+  virtual ResultCode SetDelayedIntegrityLevel(IntegrityLevel level) = 0;
+
+  // Sets a capability to be enabled for the sandboxed process' AppContainer.
+  virtual ResultCode SetCapability(const wchar_t* sid) = 0;
+
+  // Sets the LowBox token for sandboxed process. This is mutually exclusive
+  // with SetAppContainer method.
+  virtual ResultCode SetLowBox(const wchar_t* sid) = 0;
+
+  // Sets the mitigations enabled when the process is created. Most of these
+  // are implemented as attributes passed via STARTUPINFOEX. So they take
+  // effect before any thread in the target executes. The declaration of
+  // MitigationFlags is followed by a detailed description of each flag.
+  virtual ResultCode SetProcessMitigations(MitigationFlags flags) = 0;
+
+  // Returns the currently set mitigation flags.
+  virtual MitigationFlags GetProcessMitigations() = 0;
+
+  // Sets process mitigation flags that don't take effect before the call to
+  // LowerToken().
+  virtual ResultCode SetDelayedProcessMitigations(MitigationFlags flags) = 0;
+
+  // Returns the currently set delayed mitigation flags.
+  virtual MitigationFlags GetDelayedProcessMitigations() const = 0;
+
+  // Disconnect the target from CSRSS when TargetServices::LowerToken() is
+  // called inside the target.
+  virtual void SetDisconnectCsrss() = 0;
+
+  // Sets the interceptions to operate in strict mode. By default, interceptions
+  // are performed in "relaxed" mode, where if something inside NTDLL.DLL is
+  // already patched we attempt to intercept it anyway. Setting interceptions
+  // to strict mode means that when we detect that the function is patched we'll
+  // refuse to perform the interception.
+  virtual void SetStrictInterceptions() = 0;
+
+  // Set the handles the target process should inherit for stdout and
+  // stderr.  The handles the caller passes must remain valid for the
+  // lifetime of the policy object.  This only has an effect on
+  // Windows Vista and later versions.  These methods accept pipe and
+  // file handles, but not console handles.
+  virtual ResultCode SetStdoutHandle(HANDLE handle) = 0;
+  virtual ResultCode SetStderrHandle(HANDLE handle) = 0;
+
+  // Adds a policy rule effective for processes spawned using this policy.
+  // subsystem: One of the above enumerated windows subsystems.
+  // semantics: One of the above enumerated FileSemantics.
+  // pattern: A specific full path or a full path with wildcard patterns.
+  //   The valid wildcards are:
+  //   '*' : Matches zero or more character. Only one in series allowed.
+  //   '?' : Matches a single character. One or more in series are allowed.
+  // Examples:
+  //   "c:\\documents and settings\\vince\\*.dmp"
+  //   "c:\\documents and settings\\*\\crashdumps\\*.dmp"
+  //   "c:\\temp\\app_log_?????_chrome.txt"
+  virtual ResultCode AddRule(SubSystem subsystem, Semantics semantics,
+                             const wchar_t* pattern) = 0;
+
+  // Adds a dll that will be unloaded in the target process before it gets
+  // a chance to initialize itself. Typically, dlls that cause the target
+  // to crash go here.
+  virtual ResultCode AddDllToUnload(const wchar_t* dll_name) = 0;
+
+  // Adds a handle that will be closed in the target process after lockdown.
+  // A NULL value for handle_name indicates all handles of the specified type.
+  // An empty string for handle_name indicates the handle is unnamed.
+  virtual ResultCode AddKernelObjectToClose(const wchar_t* handle_type,
+                                            const wchar_t* handle_name) = 0;
+
+  // Adds a handle that will be shared with the target process. Does not take
+  // ownership of the handle.
+  virtual void AddHandleToShare(HANDLE handle) = 0;
+
+  // Locks down the default DACL of the created lockdown and initial tokens
+  // to restrict what other processes are allowed to access a process' kernel
+  // resources.
+  virtual void SetLockdownDefaultDacl() = 0;
+
+  // Enable OPM API redirection when in Win32k lockdown.
+  virtual void SetEnableOPMRedirection() = 0;
+  // Enable OPM API emulation when in Win32k lockdown.
+  virtual bool GetEnableOPMRedirection() = 0;
+};
+
+}  // namespace sandbox
+
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
diff --git a/libchrome/sandbox/win/src/sandbox_types.h b/libchrome/sandbox/win/src/sandbox_types.h
new file mode 100644
index 0000000..919086a
--- /dev/null
+++ b/libchrome/sandbox/win/src/sandbox_types.h
@@ -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.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
+#define SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
+
+#include "base/process/launch.h"
+
+namespace sandbox {
+
+// Operation result codes returned by the sandbox API.
+//
+// Note: These codes are listed in a histogram and any new codes should be added
+// at the end.
+//
+enum ResultCode : int {
+  SBOX_ALL_OK = 0,
+  // Error is originating on the win32 layer. Call GetlastError() for more
+  // information.
+  SBOX_ERROR_GENERIC = 1,
+  // An invalid combination of parameters was given to the API.
+  SBOX_ERROR_BAD_PARAMS = 2,
+  // The desired operation is not supported at this time.
+  SBOX_ERROR_UNSUPPORTED = 3,
+  // The request requires more memory that allocated or available.
+  SBOX_ERROR_NO_SPACE = 4,
+  // The ipc service requested does not exist.
+  SBOX_ERROR_INVALID_IPC = 5,
+  // The ipc service did not complete.
+  SBOX_ERROR_FAILED_IPC = 6,
+  // The requested handle was not found.
+  SBOX_ERROR_NO_HANDLE = 7,
+  // This function was not expected to be called at this time.
+  SBOX_ERROR_UNEXPECTED_CALL = 8,
+  // WaitForAllTargets is already called.
+  SBOX_ERROR_WAIT_ALREADY_CALLED = 9,
+  // A channel error prevented DoCall from executing.
+  SBOX_ERROR_CHANNEL_ERROR = 10,
+  // Failed to create the alternate desktop.
+  SBOX_ERROR_CANNOT_CREATE_DESKTOP = 11,
+  // Failed to create the alternate window station.
+  SBOX_ERROR_CANNOT_CREATE_WINSTATION = 12,
+  // Failed to switch back to the interactive window station.
+  SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION = 13,
+  // The supplied AppContainer is not valid.
+  SBOX_ERROR_INVALID_APP_CONTAINER = 14,
+  // The supplied capability is not valid.
+  SBOX_ERROR_INVALID_CAPABILITY = 15,
+  // There is a failure initializing the AppContainer.
+  SBOX_ERROR_CANNOT_INIT_APPCONTAINER = 16,
+  // Initializing or updating ProcThreadAttributes failed.
+  SBOX_ERROR_PROC_THREAD_ATTRIBUTES = 17,
+  // Error in creating process.
+  SBOX_ERROR_CREATE_PROCESS = 18,
+  // Failure calling delegate PreSpawnTarget.
+  SBOX_ERROR_DELEGATE_PRE_SPAWN = 19,
+  // Could not assign process to job object.
+  SBOX_ERROR_ASSIGN_PROCESS_TO_JOB_OBJECT = 20,
+  // Could not assign process to job object.
+  SBOX_ERROR_SET_THREAD_TOKEN = 21,
+  // Could not get thread context of new process.
+  SBOX_ERROR_GET_THREAD_CONTEXT = 22,
+  // Could not duplicate target info of new process.
+  SBOX_ERROR_DUPLICATE_TARGET_INFO = 23,
+  // Could not set low box token.
+  SBOX_ERROR_SET_LOW_BOX_TOKEN = 24,
+  // Could not create file mapping for IPC dispatcher.
+  SBOX_ERROR_CREATE_FILE_MAPPING = 25,
+  // Could not duplicate shared section into target process for IPC dispatcher.
+  SBOX_ERROR_DUPLICATE_SHARED_SECTION = 26,
+  // Could not map view of shared memory in broker.
+  SBOX_ERROR_MAP_VIEW_OF_SHARED_SECTION = 27,
+  // Could not apply ASLR mitigations to target process.
+  SBOX_ERROR_APPLY_ASLR_MITIGATIONS = 28,
+  // Could not setup one of the required interception services.
+  SBOX_ERROR_SETUP_BASIC_INTERCEPTIONS = 29,
+  // Could not setup basic interceptions.
+  SBOX_ERROR_SETUP_INTERCEPTION_SERVICE = 30,
+  // Could not initialize interceptions. This usually means 3rd party software
+  // is stomping on our hooks, or can sometimes mean the syscall format has
+  // changed.
+  SBOX_ERROR_INITIALIZE_INTERCEPTIONS = 31,
+  // Could not setup the imports for ntdll in target process.
+  SBOX_ERROR_SETUP_NTDLL_IMPORTS = 32,
+  // Could not setup the handle closer in target process.
+  SBOX_ERROR_SETUP_HANDLE_CLOSER = 33,
+  // Cannot get the current Window Station.
+  SBOX_ERROR_CANNOT_GET_WINSTATION = 34,
+  // Cannot query the security attributes of the current Window Station.
+  SBOX_ERROR_CANNOT_QUERY_WINSTATION_SECURITY = 35,
+  // Cannot get the current Desktop.
+  SBOX_ERROR_CANNOT_GET_DESKTOP = 36,
+  // Cannot query the security attributes of the current Desktop.
+  SBOX_ERROR_CANNOT_QUERY_DESKTOP_SECURITY = 37,
+  // Cannot setup the interception manager config buffer.
+  SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_CONFIG_BUFFER = 38,
+  // Cannot copy data to the child process.
+  SBOX_ERROR_CANNOT_COPY_DATA_TO_CHILD = 39,
+  // Cannot setup the interception thunk.
+  SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_THUNK = 40,
+  // Cannot resolve the interception thunk.
+  SBOX_ERROR_CANNOT_RESOLVE_INTERCEPTION_THUNK = 41,
+  // Cannot write interception thunk to child process.
+  SBOX_ERROR_CANNOT_WRITE_INTERCEPTION_THUNK = 42,
+  // Placeholder for last item of the enum.
+  SBOX_ERROR_LAST
+};
+
+// If the sandbox cannot create a secure environment for the target, the
+// target will be forcibly terminated. These are the process exit codes.
+enum TerminationCodes {
+  SBOX_FATAL_INTEGRITY = 7006,        // Could not set the integrity level.
+  SBOX_FATAL_DROPTOKEN = 7007,        // Could not lower the token.
+  SBOX_FATAL_FLUSHANDLES = 7008,      // Failed to flush registry handles.
+  SBOX_FATAL_CACHEDISABLE = 7009,     // Failed to forbid HCKU caching.
+  SBOX_FATAL_CLOSEHANDLES = 7010,     // Failed to close pending handles.
+  SBOX_FATAL_MITIGATION = 7011,       // Could not set the mitigation policy.
+  SBOX_FATAL_MEMORY_EXCEEDED = 7012,  // Exceeded the job memory limit.
+  SBOX_FATAL_WARMUP = 7013,           // Failed to warmup.
+  SBOX_FATAL_LAST
+};
+
+class BrokerServices;
+class TargetServices;
+
+// Contains the pointer to a target or broker service.
+struct SandboxInterfaceInfo {
+  BrokerServices* broker_services;
+  TargetServices* target_services;
+};
+
+#if SANDBOX_EXPORTS
+#define SANDBOX_INTERCEPT extern "C" __declspec(dllexport)
+#else
+#define SANDBOX_INTERCEPT extern "C"
+#endif
+
+enum InterceptionType {
+  INTERCEPTION_INVALID = 0,
+  INTERCEPTION_SERVICE_CALL,    // Trampoline of an NT native call
+  INTERCEPTION_EAT,
+  INTERCEPTION_SIDESTEP,        // Preamble patch
+  INTERCEPTION_SMART_SIDESTEP,  // Preamble patch but bypass internal calls
+  INTERCEPTION_UNLOAD_MODULE,   // Unload the module (don't patch)
+  INTERCEPTION_LAST             // Placeholder for last item in the enumeration
+};
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
diff --git a/libchrome/sandbox/win/src/security_level.h b/libchrome/sandbox/win/src/security_level.h
new file mode 100644
index 0000000..d8524c1
--- /dev/null
+++ b/libchrome/sandbox/win/src/security_level.h
@@ -0,0 +1,225 @@
+// 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 SANDBOX_SRC_SECURITY_LEVEL_H_
+#define SANDBOX_SRC_SECURITY_LEVEL_H_
+
+#include <stdint.h>
+
+namespace sandbox {
+
+// List of all the integrity levels supported in the sandbox. This is used
+// only on Windows Vista. You can't set the integrity level of the process
+// in the sandbox to a level higher than yours.
+enum IntegrityLevel {
+  INTEGRITY_LEVEL_SYSTEM,
+  INTEGRITY_LEVEL_HIGH,
+  INTEGRITY_LEVEL_MEDIUM,
+  INTEGRITY_LEVEL_MEDIUM_LOW,
+  INTEGRITY_LEVEL_LOW,
+  INTEGRITY_LEVEL_BELOW_LOW,
+  INTEGRITY_LEVEL_UNTRUSTED,
+  INTEGRITY_LEVEL_LAST
+};
+
+// The Token level specifies a set of  security profiles designed to
+// provide the bulk of the security of sandbox.
+//
+//  TokenLevel                 |Restricting   |Deny Only       |Privileges|
+//                             |Sids          |Sids            |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_LOCKDOWN               | Null Sid     | All            | None     |
+// ----------------------------|--------------|----------------|----------|
+// USER_RESTRICTED             | RESTRICTED   | All            | Traverse |
+// ----------------------------|--------------|----------------|----------|
+// USER_LIMITED                | Users        | All except:    | Traverse |
+//                             | Everyone     | Users          |          |
+//                             | RESTRICTED   | Everyone       |          |
+//                             |              | Interactive    |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_INTERACTIVE            | Users        | All except:    | Traverse |
+//                             | Everyone     | Users          |          |
+//                             | RESTRICTED   | Everyone       |          |
+//                             | Owner        | Interactive    |          |
+//                             |              | Local          |          |
+//                             |              | Authent-users  |          |
+//                             |              | User           |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_NON_ADMIN              | None         | All except:    | Traverse |
+//                             |              | Users          |          |
+//                             |              | Everyone       |          |
+//                             |              | Interactive    |          |
+//                             |              | Local          |          |
+//                             |              | Authent-users  |          |
+//                             |              | User           |          |
+// ----------------------------|--------------|----------------|----------|
+// USER_RESTRICTED_SAME_ACCESS | All          | None           | All      |
+// ----------------------------|--------------|----------------|----------|
+// USER_UNPROTECTED            | None         | None           | All      |
+// ----------------------------|--------------|----------------|----------|
+//
+// The above restrictions are actually a transformation that is applied to
+// the existing broker process token. The resulting token that will be
+// applied to the target process depends both on the token level selected
+// and on the broker token itself.
+//
+//  The LOCKDOWN and RESTRICTED are designed to allow access to almost
+//  nothing that has security associated with and they are the recommended
+//  levels to run sandboxed code specially if there is a chance that the
+//  broker is process might be started by a user that belongs to the Admins
+//  or power users groups.
+enum TokenLevel {
+   USER_LOCKDOWN = 0,
+   USER_RESTRICTED,
+   USER_LIMITED,
+   USER_INTERACTIVE,
+   USER_NON_ADMIN,
+   USER_RESTRICTED_SAME_ACCESS,
+   USER_UNPROTECTED,
+   USER_LAST
+};
+
+// The Job level specifies a set of decreasing security profiles for the
+// Job object that the target process will be placed into.
+// This table summarizes the security associated with each level:
+//
+//  JobLevel        |General                            |Quota               |
+//                  |restrictions                       |restrictions        |
+// -----------------|---------------------------------- |--------------------|
+// JOB_NONE         | No job is assigned to the         | None               |
+//                  | sandboxed process.                |                    |
+// -----------------|---------------------------------- |--------------------|
+// JOB_UNPROTECTED  | None                              | *Kill on Job close.|
+// -----------------|---------------------------------- |--------------------|
+// JOB_INTERACTIVE  | *Forbid system-wide changes using |                    |
+//                  |  SystemParametersInfo().          | *Kill on Job close.|
+//                  | *Forbid the creation/switch of    |                    |
+//                  |  Desktops.                        |                    |
+//                  | *Forbids calls to ExitWindows().  |                    |
+// -----------------|---------------------------------- |--------------------|
+// JOB_LIMITED_USER | Same as INTERACTIVE_USER plus:    | *One active process|
+//                  | *Forbid changes to the display    |  limit.            |
+//                  |  settings.                        | *Kill on Job close.|
+// -----------------|---------------------------------- |--------------------|
+// JOB_RESTRICTED   | Same as LIMITED_USER plus:        | *One active process|
+//                  | * No read/write to the clipboard. |  limit.            |
+//                  | * No access to User Handles that  | *Kill on Job close.|
+//                  |   belong to other processes.      |                    |
+//                  | * Forbid message broadcasts.      |                    |
+//                  | * Forbid setting global hooks.    |                    |
+//                  | * No access to the global atoms   |                    |
+//                  |   table.                          |                    |
+// -----------------|-----------------------------------|--------------------|
+// JOB_LOCKDOWN     | Same as RESTRICTED                | *One active process|
+//                  |                                   |  limit.            |
+//                  |                                   | *Kill on Job close.|
+//                  |                                   | *Kill on unhandled |
+//                  |                                   |  exception.        |
+//                  |                                   |                    |
+// In the context of the above table, 'user handles' refers to the handles of
+// windows, bitmaps, menus, etc. Files, treads and registry handles are kernel
+// handles and are not affected by the job level settings.
+enum JobLevel {
+  JOB_LOCKDOWN = 0,
+  JOB_RESTRICTED,
+  JOB_LIMITED_USER,
+  JOB_INTERACTIVE,
+  JOB_UNPROTECTED,
+  JOB_NONE
+};
+
+// These flags correspond to various process-level mitigations (eg. ASLR and
+// DEP). Most are implemented via UpdateProcThreadAttribute() plus flags for
+// the PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY attribute argument; documented
+// here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686880
+// Some mitigations are implemented directly by the sandbox or emulated to
+// the greatest extent possible when not directly supported by the OS.
+// Flags that are unsupported for the target OS will be silently ignored.
+// Flags that are invalid for their application (pre or post startup) will
+// return SBOX_ERROR_BAD_PARAMS.
+typedef uint64_t MitigationFlags;
+
+// Permanently enables DEP for the target process. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE.
+const MitigationFlags MITIGATION_DEP                              = 0x00000001;
+
+// Permanently Disables ATL thunk emulation when DEP is enabled. Valid
+// only when MITIGATION_DEP is passed. Corresponds to not passing
+// PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE.
+const MitigationFlags MITIGATION_DEP_NO_ATL_THUNK                 = 0x00000002;
+
+// Enables Structured exception handling override prevention. Must be
+// enabled prior to process start. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE.
+const MitigationFlags MITIGATION_SEHOP                            = 0x00000004;
+
+// Forces ASLR on all images in the child process. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON .
+const MitigationFlags MITIGATION_RELOCATE_IMAGE                   = 0x00000008;
+
+// Refuses to load DLLs that cannot support ASLR. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS.
+const MitigationFlags MITIGATION_RELOCATE_IMAGE_REQUIRED          = 0x00000010;
+
+// Terminates the process on Windows heap corruption. Coresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON.
+const MitigationFlags MITIGATION_HEAP_TERMINATE                   = 0x00000020;
+
+// Sets a random lower bound as the minimum user address. Must be
+// enabled prior to process start. On 32-bit processes this is
+// emulated to a much smaller degree. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON.
+const MitigationFlags MITIGATION_BOTTOM_UP_ASLR                   = 0x00000040;
+
+// Increases the randomness range of bottom-up ASLR to up to 1TB. Must be
+// enabled prior to process start and with MITIGATION_BOTTOM_UP_ASLR.
+// Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON
+const MitigationFlags MITIGATION_HIGH_ENTROPY_ASLR                = 0x00000080;
+
+// Immediately raises an exception on a bad handle reference. Must be
+// enabled after startup. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON.
+const MitigationFlags MITIGATION_STRICT_HANDLE_CHECKS             = 0x00000100;
+
+// Prevents the process from making Win32k calls. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON.
+const MitigationFlags MITIGATION_WIN32K_DISABLE                   = 0x00000200;
+
+// Prevents certain built-in third party extension points from being used.
+// - App_Init DLLs
+// - Winsock Layered Service Providers (LSPs)
+// - Global Windows Hooks (NOT thread-targeted hooks)
+// - Legacy Input Method Editors (IMEs).
+// I.e.: Disable legacy hooking mechanisms.  Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON.
+const MitigationFlags MITIGATION_EXTENSION_POINT_DISABLE = 0x00000400;
+
+// Prevents the process from loading non-system fonts into GDI.
+// Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON
+const MitigationFlags MITIGATION_NONSYSTEM_FONT_DISABLE = 0x00000800;
+
+// Sets the DLL search order to LOAD_LIBRARY_SEARCH_DEFAULT_DIRS. Additional
+// directories can be added via the Windows AddDllDirectory() function.
+// http://msdn.microsoft.com/en-us/library/windows/desktop/hh310515
+// Must be enabled after startup.
+const MitigationFlags MITIGATION_DLL_SEARCH_ORDER        = 0x00000001ULL << 32;
+
+// Changes the mandatory integrity level policy on the current process' token
+// to enable no-read and no-execute up. This prevents a lower IL process from
+// opening the process token for impersonate/duplicate/assignment.
+const MitigationFlags MITIGATION_HARDEN_TOKEN_IL_POLICY  = 0x00000001ULL << 33;
+
+// Blocks mapping of images from remote devices. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON.
+const MitigationFlags MITIGATION_IMAGE_LOAD_NO_REMOTE = 0x00000001ULL << 52;
+
+// Blocks mapping of images that have the low manditory label. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON.
+const MitigationFlags MITIGATION_IMAGE_LOAD_NO_LOW_LABEL = 0x00000001ULL << 56;
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_SRC_SECURITY_LEVEL_H_
diff --git a/libchrome/sandbox/win/src/sidestep/ia32_modrm_map.cpp b/libchrome/sandbox/win/src/sidestep/ia32_modrm_map.cpp
new file mode 100644
index 0000000..89bc189
--- /dev/null
+++ b/libchrome/sandbox/win/src/sidestep/ia32_modrm_map.cpp
@@ -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.
+
+// Table of relevant information about how to decode the ModR/M byte.
+// Based on information in the IA-32 Intel Architecture
+// Software Developer's Manual Volume 2: Instruction Set Reference.
+
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+#include "sandbox/win/src/sidestep/mini_disassembler_types.h"
+
+namespace sidestep {
+
+const ModrmEntry MiniDisassembler::s_ia16_modrm_map_[] = {
+// mod == 00
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, false, OS_ZERO },
+  /* r/m == 101 */ { false, false, OS_ZERO },
+  /* r/m == 110 */ { true, false, OS_WORD },
+  /* r/m == 111 */ { false, false, OS_ZERO },
+// mod == 01
+  /* r/m == 000 */ { true, false, OS_BYTE },
+  /* r/m == 001 */ { true, false, OS_BYTE },
+  /* r/m == 010 */ { true, false, OS_BYTE },
+  /* r/m == 011 */ { true, false, OS_BYTE },
+  /* r/m == 100 */ { true, false, OS_BYTE },
+  /* r/m == 101 */ { true, false, OS_BYTE },
+  /* r/m == 110 */ { true, false, OS_BYTE },
+  /* r/m == 111 */ { true, false, OS_BYTE },
+// mod == 10
+  /* r/m == 000 */ { true, false, OS_WORD },
+  /* r/m == 001 */ { true, false, OS_WORD },
+  /* r/m == 010 */ { true, false, OS_WORD },
+  /* r/m == 011 */ { true, false, OS_WORD },
+  /* r/m == 100 */ { true, false, OS_WORD },
+  /* r/m == 101 */ { true, false, OS_WORD },
+  /* r/m == 110 */ { true, false, OS_WORD },
+  /* r/m == 111 */ { true, false, OS_WORD },
+// mod == 11
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, false, OS_ZERO },
+  /* r/m == 101 */ { false, false, OS_ZERO },
+  /* r/m == 110 */ { false, false, OS_ZERO },
+  /* r/m == 111 */ { false, false, OS_ZERO }
+};
+
+const ModrmEntry MiniDisassembler::s_ia32_modrm_map_[] = {
+// mod == 00
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, true, OS_ZERO },
+  /* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 110 */ { false, false, OS_ZERO },
+  /* r/m == 111 */ { false, false, OS_ZERO },
+// mod == 01
+  /* r/m == 000 */ { true, false, OS_BYTE },
+  /* r/m == 001 */ { true, false, OS_BYTE },
+  /* r/m == 010 */ { true, false, OS_BYTE },
+  /* r/m == 011 */ { true, false, OS_BYTE },
+  /* r/m == 100 */ { true, true, OS_BYTE },
+  /* r/m == 101 */ { true, false, OS_BYTE },
+  /* r/m == 110 */ { true, false, OS_BYTE },
+  /* r/m == 111 */ { true, false, OS_BYTE },
+// mod == 10
+  /* r/m == 000 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 001 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 010 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 011 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 100 */ { true, true, OS_DOUBLE_WORD },
+  /* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 110 */ { true, false, OS_DOUBLE_WORD },
+  /* r/m == 111 */ { true, false, OS_DOUBLE_WORD },
+// mod == 11
+  /* r/m == 000 */ { false, false, OS_ZERO },
+  /* r/m == 001 */ { false, false, OS_ZERO },
+  /* r/m == 010 */ { false, false, OS_ZERO },
+  /* r/m == 011 */ { false, false, OS_ZERO },
+  /* r/m == 100 */ { false, false, OS_ZERO },
+  /* r/m == 101 */ { false, false, OS_ZERO },
+  /* r/m == 110 */ { false, false, OS_ZERO },
+  /* r/m == 111 */ { false, false, OS_ZERO },
+};
+
+};  // namespace sidestep
diff --git a/libchrome/sandbox/win/src/sidestep/ia32_opcode_map.cpp b/libchrome/sandbox/win/src/sidestep/ia32_opcode_map.cpp
new file mode 100644
index 0000000..b7d8a60
--- /dev/null
+++ b/libchrome/sandbox/win/src/sidestep/ia32_opcode_map.cpp
@@ -0,0 +1,1159 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Opcode decoding maps.  Based on the IA-32 Intel Architecture
+// Software Developer's Manual Volume 2: Instruction Set Reference.  Idea
+// for how to lay out the tables in memory taken from the implementation
+// in the Bastard disassembly environment.
+
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+
+namespace sidestep {
+
+/*
+* This is the first table to be searched; the first field of each
+* Opcode in the table is either 0 to indicate you're in the
+* right table, or an index to the correct table, in the global
+* map g_pentiumOpcodeMap
+*/
+const Opcode s_first_opcode_byte[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF */ { 1, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x10 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x11 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x12 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x13 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x14 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x15 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x16 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x17 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x18 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x19 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1E */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1F */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x20 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x21 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x22 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x23 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x24 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x25 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x26 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x27 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "daa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x28 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x29 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "das", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x30 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x31 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x32 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x33 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x34 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x35 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x36 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x37 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aaa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x38 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x39 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aas", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x40 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x41 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x42 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x43 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x44 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x45 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x46 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x47 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x48 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x49 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x50 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x51 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x52 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x53 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x54 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x55 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x56 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x57 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x58 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x59 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x60 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x61 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x62 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_A, AM_NOT_USED, "bound", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x63 */ { 0, IT_GENERIC, AM_E | OT_W, AM_G | OT_W, AM_NOT_USED, "arpl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x64 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x65 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x66 */ { 0, IT_PREFIX_OPERAND, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x67 */ { 0, IT_PREFIX_ADDRESS, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x68 */ { 0, IT_GENERIC, AM_I | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x69 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I | OT_V, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6A */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I |  OT_B, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6C */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "insb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6D */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "insd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6E */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X | OT_B, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X | OT_V, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x70 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x71 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x72 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x73 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x74 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x75 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x76 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x77 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x78 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x79 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7A */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7B */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7C */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7D */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7E */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7F */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x80 */ { 2, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x81 */ { 3, IT_REFERENCE, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x82 */ { 4, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x83 */ { 5, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x84 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x85 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x86 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x87 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x88 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x89 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8C */ { 0, IT_GENERIC, AM_E | OT_W, AM_S | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8D */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, "lea", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8E */ { 0, IT_GENERIC, AM_S | OT_W, AM_E | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8F */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x90 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "nop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x91 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x92 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x93 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x94 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x95 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x96 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x97 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x98 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cwde", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x99 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cdq", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9A */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "callf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9B */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wait", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9E */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_O | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_O | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA2 */ { 0, IT_GENERIC, AM_O | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA3 */ { 0, IT_GENERIC, AM_O | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA4 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "movsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA5 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "movsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA6 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "cmpsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA7 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "cmpsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAA */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "stosb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAB */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "stosd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X| OT_B, AM_NOT_USED, "lodsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X| OT_V, AM_NOT_USED, "lodsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAE */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_Y | OT_B, AM_NOT_USED, "scasb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_Y | OT_V, AM_NOT_USED, "scasd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB1 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB2 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB3 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB8 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBA */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBB */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBC */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBE */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC0 */ { 6, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC1 */ { 7, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC2 */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC3 */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC4 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "les", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "lds", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC8 */ { 0, IT_GENERIC, AM_I | OT_W, AM_I | OT_B, AM_NOT_USED, "enter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "leave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCA */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCB */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "int3", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCD */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "int", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCE */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "into", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCF */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "iret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD0 */ { 8, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD1 */ { 9, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD2 */ { 10, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD3 */ { 11, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD4 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aam", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD5 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "xlat", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+  // The following 8 lines would be references to the FPU tables, but we currently
+  // do not support the FPU instructions in this disassembler.
+
+  /* 0xD8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDA */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDB */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDC */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDD */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDE */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDF */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+
+  /* 0xE0 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE1 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE2 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE3 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jcxz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE6 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE7 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE8 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE9 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEA */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEB */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xED */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEF */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_V, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF0 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lock:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF2 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "repne:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF3 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rep:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF4 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "hlt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF6 */ { 12, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF7 */ { 13, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cli", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFB */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFD */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "std", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFE */ { 14, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFF */ { 15, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f[] = {
+  /* 0x0 */ { 16, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 17, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lsl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "invd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wbinvd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud2", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x10 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movups", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "movsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "movss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movupd" } },
+  /* 0x11 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movups", true,
+    /* F2h */ { 0, IT_GENERIC, AM_W | OT_SD, AM_V | OT_SD, AM_NOT_USED, "movsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_W | OT_SS, AM_V | OT_SS, AM_NOT_USED, "movss" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movupd" } },
+  /* 0x12 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // only one of ...
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // ...these two is correct, Intel doesn't specify which
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_S, AM_NOT_USED, "movlpd" } },
+  /* 0x13 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlpd" } },
+  /* 0x14 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpcklps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpcklpd" } },
+  /* 0x15 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpckhps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpckhpd" } },
+  /* 0x16 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // only one of...
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // ...these two is correct, Intel doesn't specify which
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhpd" } },
+  /* 0x17 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhpd" } },
+  /* 0x18 */ { 18, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x19 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1C */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x20 */ { 0, IT_GENERIC, AM_R | OT_D, AM_C | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x21 */ { 0, IT_GENERIC, AM_R | OT_D, AM_D | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x22 */ { 0, IT_GENERIC, AM_C | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x23 */ { 0, IT_GENERIC, AM_D | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x24 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x25 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x26 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x27 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x28 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movaps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movapd" } },
+  /* 0x29 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movaps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movapd" } },
+  /* 0x2A */ { 0, IT_GENERIC, AM_V | OT_PS, AM_Q | OT_Q, AM_NOT_USED, "cvtpi2ps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_E | OT_D, AM_NOT_USED, "cvtsi2sd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_E | OT_D, AM_NOT_USED, "cvtsi2ss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_Q | OT_DQ, AM_NOT_USED, "cvtpi2pd" } },
+  /* 0x2B */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movntps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movntpd" } },
+  /* 0x2C */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvttps2pi", true,
+    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvttsd2si" },
+    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvttss2si" },
+    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2pi" } },
+  /* 0x2D */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvtps2pi", true,
+    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvtsd2si" },
+    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvtss2si" },
+    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2pi" } },
+  /* 0x2E */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "ucomiss", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "ucomisd" } },
+  /* 0x2F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_SS, AM_NOT_USED, "comiss", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "comisd" } },
+  /* 0x30 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wrmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x31 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdtsc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x32 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x33 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdpmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x34 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysenter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x35 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysexit", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x36 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x37 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x38 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x39 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x40 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x41 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x42 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x43 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x44 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x45 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x46 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x47 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmova", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x48 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x49 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4A */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4D */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4E */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4F */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x50 */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PS, AM_NOT_USED, "movmskps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PD, AM_NOT_USED, "movmskpd" } },
+  /* 0x51 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "sqrtps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "sqrtsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "sqrtss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "sqrtpd" } },
+  /* 0x52 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rsqrtps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rsqrtss" },
+    /* 66h */ { 0 } },
+  /* 0x53 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rcpps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rcpss" },
+    /* 66h */ { 0 } },
+  /* 0x54 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andpd" } },
+  /* 0x55 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andnps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andnpd" } },
+  /* 0x56 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "orps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "orpd" } },
+  /* 0x57 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "xorps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "xorpd" } },
+  /* 0x58 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "addps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "addsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "addss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "addpd" } },
+  /* 0x59 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "mulps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "mulsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "mulss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "mulpd" } },
+  /* 0x5A */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PS, AM_NOT_USED, "cvtps2pd", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "cvtsd2ss" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "cvtss2sd" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PD, AM_NOT_USED, "cvtpd2ps" } },
+  /* 0x5B */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2ps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvttps2dq" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvtps2dq" } },
+  /* 0x5C */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "subps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "subsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "subss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "subpd" } },
+  /* 0x5D */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "minps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "minsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "minss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "minpd" } },
+  /* 0x5E */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "divps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "divsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "divss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "divpd" } },
+  /* 0x5F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "maxps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "maxsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "maxss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "maxpd" } },
+  /* 0x60 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklbw" } },
+  /* 0x61 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklwd" } },
+  /* 0x62 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckldq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpckldq" } },
+  /* 0x63 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packsswb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packsswb" } },
+  /* 0x64 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtb" } },
+  /* 0x65 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtw" } },
+  /* 0x66 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtd" } },
+  /* 0x67 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packuswb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packuswb" } },
+  /* 0x68 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhbw" } },
+  /* 0x69 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhwd" } },
+  /* 0x6A */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhdq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhdq" } },
+  /* 0x6B */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packssdw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "packssdw" } },
+  /* 0x6C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
+  /* 0x6D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
+  /* 0x6E */ { 0, IT_GENERIC, AM_P | OT_D, AM_E | OT_D, AM_NOT_USED, "movd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_NOT_USED, "movd" } },
+  /* 0x6F */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "movq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqu" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqa" } },
+  /* 0x70 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_I |  OT_B, "pshuf", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshuflw" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufhw" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufd" } },
+  /* 0x71 */ { 19, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x72 */ { 20, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x73 */ { 21, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x74 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqb" } },
+  /* 0x75 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqw" } },
+  /* 0x76 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqd" } },
+  /* 0x77 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "emms", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+  // The following six opcodes are escapes into the MMX stuff, which this disassembler does not support.
+  /* 0x78 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x79 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7A */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7B */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7C */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7D */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+
+  /* 0x7E */ { 0, IT_GENERIC, AM_E | OT_D, AM_P | OT_D, AM_NOT_USED, "movd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movq" },
+    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_DQ, AM_NOT_USED, "movd" } },
+  /* 0x7F */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_P | OT_Q, AM_NOT_USED, "movq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqu" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqa" } },
+  /* 0x80 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x81 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x82 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x83 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x84 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x85 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x86 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x87 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x88 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x89 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8A */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8B */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8C */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8D */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8E */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8F */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x90 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seto", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x91 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x92 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x93 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x94 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x95 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x96 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x97 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seta", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x98 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "sets", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x99 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9A */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9B */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9C */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9D */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9E */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9F */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cpuid", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA6 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA7 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rsm", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAC */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAD */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAE */ { 22, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB2 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lss", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB4 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lfs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB5 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lgs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB6 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB7 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud1", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBA */ { 23, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBC */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBD */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBE */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC2 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "cmpps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_I | OT_B, "cmpsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W  | OT_SS, AM_I | OT_B, "cmpss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "cmppd" } },
+  /* 0xC3 */ { 0, IT_GENERIC, AM_E | OT_D, AM_G | OT_D, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_E | OT_D, AM_I | OT_B, "pinsrw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_I | OT_B, "pinsrw" } },
+  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_I | OT_B, "pextrw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_I | OT_B, "pextrw" } },
+  /* 0xC6 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "shufps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "shufpd" } },
+  /* 0xC7 */ { 24, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC8 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC9 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCA */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCB */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCC */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCD */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCE */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCF */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlw" } },
+  /* 0xD2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrld" } },
+  /* 0xD3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlq" } },
+  /* 0xD4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddq" } },
+  /* 0xD5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmullw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmullw" } },
+  /* 0xD6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "unused without prefix", true,
+    /* F2h */ { 0, IT_GENERIC, AM_P | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movdq2q" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_Q | OT_Q, AM_NOT_USED, "movq2dq" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movq" } },
+  /* 0xD7 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_NOT_USED, "pmovmskb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_NOT_USED, "pmovmskb" } },
+  /* 0xD8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusb" } },
+  /* 0xD9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusw" } },
+  /* 0xDA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminub", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminub" } },
+  /* 0xDB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pand", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pand" } },
+  /* 0xDC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusb" } },
+  /* 0xDD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusw" } },
+  /* 0xDE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxub", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxub" } },
+  /* 0xDF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pandn", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pandn" } },
+  /* 0xE0 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgb" } },
+  /* 0xE1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psraw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrqw" } },
+  /* 0xE2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrad", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrad" } },
+  /* 0xE3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgw" } },
+  /* 0xE4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhuw" } },
+  /* 0xE5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhw" } },
+  /* 0xE6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2dq" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2pd" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2dq" } },
+  /* 0xE7 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movntq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movntdq" } },
+  /* 0xE8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsb" } },
+  /* 0xE9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsw" } },
+  /* 0xEA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminsw" } },
+  /* 0xEB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "por", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "por" } },
+  /* 0xEC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsb" } },
+  /* 0xED */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsw" } },
+  /* 0xEE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxsw" } },
+  /* 0xEF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pxor", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pxor" } },
+  /* 0xF0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllw" } },
+  /* 0xF2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pslld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pslld" } },
+  /* 0xF3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllq" } },
+  /* 0xF4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmuludq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmuludq" } },
+  /* 0xF5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaddwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaddwd" } },
+  /* 0xF6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psadbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psadbw" } },
+  /* 0xF7 */ { 0, IT_GENERIC, AM_P | OT_PI, AM_Q | OT_PI, AM_NOT_USED, "maskmovq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "maskmovdqu" } },
+  /* 0xF8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubb" } },
+  /* 0xF9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubw" } },
+  /* 0xFA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubd" } },
+  /* 0xFB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubq" } },
+  /* 0xFC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddb" } },
+  /* 0xFD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddw" } },
+  /* 0xFE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddd" } },
+  /* 0xFF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f00[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "sldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "str", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "ltr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f01[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "smsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lmsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_M | OT_B, AM_NOT_USED, AM_NOT_USED, "invlpg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f18[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f71[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlw" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psraw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psraw" } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllw" } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f72[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrld" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrad", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrad" } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "pslld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslld" } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f73[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlq" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllq" } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq" } },
+};
+
+const Opcode s_opcode_byte_after_0fae[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxsave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxrstor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ldmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "mfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clflush/sfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+};
+
+const Opcode s_opcode_byte_after_0fba[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0fc7[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_Q, AM_NOT_USED, AM_NOT_USED, "cmpxch8b", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_80[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_81[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_82[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_83[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_c0[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_c1[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d0[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d1[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d2[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d3[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_f6[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_f7[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_fe[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_ff[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+/*
+* A table of all the other tables, containing some extra information, e.g.
+* how to mask out the byte we're looking at.
+*/
+const OpcodeTable MiniDisassembler::s_ia32_opcode_map_[]={
+  // One-byte opcodes and jumps to larger
+  /*  0 */ {s_first_opcode_byte, 0, 0xff, 0, 0xff},
+  // Two-byte opcodes (second byte)
+  /*  1 */ {s_opcode_byte_after_0f, 0, 0xff, 0, 0xff},
+  // Start of tables for opcodes using ModR/M bits as extension
+  /*  2 */ {s_opcode_byte_after_80, 3, 0x07, 0, 0x07},
+  /*  3 */ {s_opcode_byte_after_81, 3, 0x07, 0, 0x07},
+  /*  4 */ {s_opcode_byte_after_82, 3, 0x07, 0, 0x07},
+  /*  5 */ {s_opcode_byte_after_83, 3, 0x07, 0, 0x07},
+  /*  6 */ {s_opcode_byte_after_c0, 3, 0x07, 0, 0x07},
+  /*  7 */ {s_opcode_byte_after_c1, 3, 0x07, 0, 0x07},
+  /*  8 */ {s_opcode_byte_after_d0, 3, 0x07, 0, 0x07},
+  /*  9 */ {s_opcode_byte_after_d1, 3, 0x07, 0, 0x07},
+  /* 10 */ {s_opcode_byte_after_d2, 3, 0x07, 0, 0x07},
+  /* 11 */ {s_opcode_byte_after_d3, 3, 0x07, 0, 0x07},
+  /* 12 */ {s_opcode_byte_after_f6, 3, 0x07, 0, 0x07},
+  /* 13 */ {s_opcode_byte_after_f7, 3, 0x07, 0, 0x07},
+  /* 14 */ {s_opcode_byte_after_fe, 3, 0x07, 0, 0x01},
+  /* 15 */ {s_opcode_byte_after_ff, 3, 0x07, 0, 0x07},
+  /* 16 */ {s_opcode_byte_after_0f00, 3, 0x07, 0, 0x07},
+  /* 17 */ {s_opcode_byte_after_0f01, 3, 0x07, 0, 0x07},
+  /* 18 */ {s_opcode_byte_after_0f18, 3, 0x07, 0, 0x07},
+  /* 19 */ {s_opcode_byte_after_0f71, 3, 0x07, 0, 0x07},
+  /* 20 */ {s_opcode_byte_after_0f72, 3, 0x07, 0, 0x07},
+  /* 21 */ {s_opcode_byte_after_0f73, 3, 0x07, 0, 0x07},
+  /* 22 */ {s_opcode_byte_after_0fae, 3, 0x07, 0, 0x07},
+  /* 23 */ {s_opcode_byte_after_0fba, 3, 0x07, 0, 0x07},
+  /* 24 */ {s_opcode_byte_after_0fc7, 3, 0x07, 0, 0x01}
+};
+
+};  // namespace sidestep
diff --git a/libchrome/sandbox/win/src/sidestep/mini_disassembler.cpp b/libchrome/sandbox/win/src/sidestep/mini_disassembler.cpp
new file mode 100644
index 0000000..1e8e0bd
--- /dev/null
+++ b/libchrome/sandbox/win/src/sidestep/mini_disassembler.cpp
@@ -0,0 +1,395 @@
+// Copyright (c) 2012 The Chromium 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 MiniDisassembler.
+
+#ifdef _WIN64
+#error The code in this file should not be used on 64-bit Windows.
+#endif
+
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+
+namespace sidestep {
+
+MiniDisassembler::MiniDisassembler(bool operand_default_is_32_bits,
+                                   bool address_default_is_32_bits)
+    : operand_default_is_32_bits_(operand_default_is_32_bits),
+      address_default_is_32_bits_(address_default_is_32_bits) {
+  Initialize();
+}
+
+MiniDisassembler::MiniDisassembler()
+    : operand_default_is_32_bits_(true),
+      address_default_is_32_bits_(true) {
+  Initialize();
+}
+
+InstructionType MiniDisassembler::Disassemble(
+    unsigned char* start_byte,
+    unsigned int* instruction_bytes) {
+  // Clean up any state from previous invocations.
+  Initialize();
+
+  // Start by processing any prefixes.
+  unsigned char* current_byte = start_byte;
+  unsigned int size = 0;
+  InstructionType instruction_type = ProcessPrefixes(current_byte, &size);
+
+  if (IT_UNKNOWN == instruction_type)
+    return instruction_type;
+
+  current_byte += size;
+  size = 0;
+
+  // Invariant: We have stripped all prefixes, and the operand_is_32_bits_
+  // and address_is_32_bits_ flags are correctly set.
+
+  instruction_type = ProcessOpcode(current_byte, 0, &size);
+
+  // Check for error processing instruction
+  if ((IT_UNKNOWN == instruction_type_) || (IT_UNUSED == instruction_type_)) {
+    return IT_UNKNOWN;
+  }
+
+  current_byte += size;
+
+  // Invariant: operand_bytes_ indicates the total size of operands
+  // specified by the opcode and/or ModR/M byte and/or SIB byte.
+  // pCurrentByte points to the first byte after the ModR/M byte, or after
+  // the SIB byte if it is present (i.e. the first byte of any operands
+  // encoded in the instruction).
+
+  // We get the total length of any prefixes, the opcode, and the ModR/M and
+  // SIB bytes if present, by taking the difference of the original starting
+  // address and the current byte (which points to the first byte of the
+  // operands if present, or to the first byte of the next instruction if
+  // they are not).  Adding the count of bytes in the operands encoded in
+  // the instruction gives us the full length of the instruction in bytes.
+  *instruction_bytes += operand_bytes_ + (current_byte - start_byte);
+
+  // Return the instruction type, which was set by ProcessOpcode().
+  return instruction_type_;
+}
+
+void MiniDisassembler::Initialize() {
+  operand_is_32_bits_ = operand_default_is_32_bits_;
+  address_is_32_bits_ = address_default_is_32_bits_;
+  operand_bytes_ = 0;
+  have_modrm_ = false;
+  should_decode_modrm_ = false;
+  instruction_type_ = IT_UNKNOWN;
+  got_f2_prefix_ = false;
+  got_f3_prefix_ = false;
+  got_66_prefix_ = false;
+}
+
+InstructionType MiniDisassembler::ProcessPrefixes(unsigned char* start_byte,
+                                                  unsigned int* size) {
+  InstructionType instruction_type = IT_GENERIC;
+  const Opcode& opcode = s_ia32_opcode_map_[0].table_[*start_byte];
+
+  switch (opcode.type_) {
+    case IT_PREFIX_ADDRESS:
+      address_is_32_bits_ = !address_default_is_32_bits_;
+      goto nochangeoperand;
+    case IT_PREFIX_OPERAND:
+      operand_is_32_bits_ = !operand_default_is_32_bits_;
+      nochangeoperand:
+    case IT_PREFIX:
+
+      if (0xF2 == (*start_byte))
+        got_f2_prefix_ = true;
+      else if (0xF3 == (*start_byte))
+        got_f3_prefix_ = true;
+      else if (0x66 == (*start_byte))
+        got_66_prefix_ = true;
+
+      instruction_type = opcode.type_;
+      (*size)++;
+      // we got a prefix, so add one and check next byte
+      ProcessPrefixes(start_byte + 1, size);
+    default:
+      break;   // not a prefix byte
+  }
+
+  return instruction_type;
+}
+
+InstructionType MiniDisassembler::ProcessOpcode(unsigned char* start_byte,
+                                                unsigned int table_index,
+                                                unsigned int* size) {
+  const OpcodeTable& table = s_ia32_opcode_map_[table_index];   // Get our table
+  unsigned char current_byte = (*start_byte) >> table.shift_;
+  current_byte = current_byte & table.mask_;  // Mask out the bits we will use
+
+  // Check whether the byte we have is inside the table we have.
+  if (current_byte < table.min_lim_ || current_byte > table.max_lim_) {
+    instruction_type_ = IT_UNKNOWN;
+    return instruction_type_;
+  }
+
+  const Opcode& opcode = table.table_[current_byte];
+  if (IT_UNUSED == opcode.type_) {
+    // This instruction is not used by the IA-32 ISA, so we indicate
+    // this to the user.  Probably means that we were pointed to
+    // a byte in memory that was not the start of an instruction.
+    instruction_type_ = IT_UNUSED;
+    return instruction_type_;
+  } else if (IT_REFERENCE == opcode.type_) {
+    // We are looking at an opcode that has more bytes (or is continued
+    // in the ModR/M byte).  Recursively find the opcode definition in
+    // the table for the opcode's next byte.
+    (*size)++;
+    ProcessOpcode(start_byte + 1, opcode.table_index_, size);
+    return instruction_type_;
+  }
+
+  const SpecificOpcode* specific_opcode = reinterpret_cast<
+                                              const SpecificOpcode*>(&opcode);
+  if (opcode.is_prefix_dependent_) {
+    if (got_f2_prefix_ && opcode.opcode_if_f2_prefix_.mnemonic_ != 0) {
+      specific_opcode = &opcode.opcode_if_f2_prefix_;
+    } else if (got_f3_prefix_ && opcode.opcode_if_f3_prefix_.mnemonic_ != 0) {
+      specific_opcode = &opcode.opcode_if_f3_prefix_;
+    } else if (got_66_prefix_ && opcode.opcode_if_66_prefix_.mnemonic_ != 0) {
+      specific_opcode = &opcode.opcode_if_66_prefix_;
+    }
+  }
+
+  // Inv: The opcode type is known.
+  instruction_type_ = specific_opcode->type_;
+
+  // Let's process the operand types to see if we have any immediate
+  // operands, and/or a ModR/M byte.
+
+  ProcessOperand(specific_opcode->flag_dest_);
+  ProcessOperand(specific_opcode->flag_source_);
+  ProcessOperand(specific_opcode->flag_aux_);
+
+  // Inv: We have processed the opcode and incremented operand_bytes_
+  // by the number of bytes of any operands specified by the opcode
+  // that are stored in the instruction (not registers etc.).  Now
+  // we need to return the total number of bytes for the opcode and
+  // for the ModR/M or SIB bytes if they are present.
+
+  if (table.mask_ != 0xff) {
+    if (have_modrm_) {
+      // we're looking at a ModR/M byte so we're not going to
+      // count that into the opcode size
+      ProcessModrm(start_byte, size);
+      return IT_GENERIC;
+    } else {
+      // need to count the ModR/M byte even if it's just being
+      // used for opcode extension
+      (*size)++;
+      return IT_GENERIC;
+    }
+  } else {
+    if (have_modrm_) {
+      // The ModR/M byte is the next byte.
+      (*size)++;
+      ProcessModrm(start_byte + 1, size);
+      return IT_GENERIC;
+    } else {
+      (*size)++;
+      return IT_GENERIC;
+    }
+  }
+}
+
+bool MiniDisassembler::ProcessOperand(int flag_operand) {
+  bool succeeded = true;
+  if (AM_NOT_USED == flag_operand)
+    return succeeded;
+
+  // Decide what to do based on the addressing mode.
+  switch (flag_operand & AM_MASK) {
+    // No ModR/M byte indicated by these addressing modes, and no
+    // additional (e.g. immediate) parameters.
+    case AM_A:  // Direct address
+    case AM_F:  // EFLAGS register
+    case AM_X:  // Memory addressed by the DS:SI register pair
+    case AM_Y:  // Memory addressed by the ES:DI register pair
+    case AM_IMPLICIT:  // Parameter is implicit, occupies no space in
+                       // instruction
+      break;
+
+    // There is a ModR/M byte but it does not necessarily need
+    // to be decoded.
+    case AM_C:  // reg field of ModR/M selects a control register
+    case AM_D:  // reg field of ModR/M selects a debug register
+    case AM_G:  // reg field of ModR/M selects a general register
+    case AM_P:  // reg field of ModR/M selects an MMX register
+    case AM_R:  // mod field of ModR/M may refer only to a general register
+    case AM_S:  // reg field of ModR/M selects a segment register
+    case AM_T:  // reg field of ModR/M selects a test register
+    case AM_V:  // reg field of ModR/M selects a 128-bit XMM register
+      have_modrm_ = true;
+      break;
+
+    // In these addressing modes, there is a ModR/M byte and it needs to be
+    // decoded. No other (e.g. immediate) params than indicated in ModR/M.
+    case AM_E:  // Operand is either a general-purpose register or memory,
+                // specified by ModR/M byte
+    case AM_M:  // ModR/M byte will refer only to memory
+    case AM_Q:  // Operand is either an MMX register or memory (complex
+                // evaluation), specified by ModR/M byte
+    case AM_W:  // Operand is either a 128-bit XMM register or memory (complex
+                // eval), specified by ModR/M byte
+      have_modrm_ = true;
+      should_decode_modrm_ = true;
+      break;
+
+    // These addressing modes specify an immediate or an offset value
+    // directly, so we need to look at the operand type to see how many
+    // bytes.
+    case AM_I:  // Immediate data.
+    case AM_J:  // Jump to offset.
+    case AM_O:  // Operand is at offset.
+      switch (flag_operand & OT_MASK) {
+        case OT_B:  // Byte regardless of operand-size attribute.
+          operand_bytes_ += OS_BYTE;
+          break;
+        case OT_C:  // Byte or word, depending on operand-size attribute.
+          if (operand_is_32_bits_)
+            operand_bytes_ += OS_WORD;
+          else
+            operand_bytes_ += OS_BYTE;
+          break;
+        case OT_D:  // Doubleword, regardless of operand-size attribute.
+          operand_bytes_ += OS_DOUBLE_WORD;
+          break;
+        case OT_DQ:  // Double-quadword, regardless of operand-size attribute.
+          operand_bytes_ += OS_DOUBLE_QUAD_WORD;
+          break;
+        case OT_P:  // 32-bit or 48-bit pointer, depending on operand-size
+                    // attribute.
+          if (operand_is_32_bits_)
+            operand_bytes_ += OS_48_BIT_POINTER;
+          else
+            operand_bytes_ += OS_32_BIT_POINTER;
+          break;
+        case OT_PS:  // 128-bit packed single-precision floating-point data.
+          operand_bytes_ += OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING;
+          break;
+        case OT_Q:  // Quadword, regardless of operand-size attribute.
+          operand_bytes_ += OS_QUAD_WORD;
+          break;
+        case OT_S:  // 6-byte pseudo-descriptor.
+          operand_bytes_ += OS_PSEUDO_DESCRIPTOR;
+          break;
+        case OT_SD:  // Scalar Double-Precision Floating-Point Value
+        case OT_PD:  // Unaligned packed double-precision floating point value
+          operand_bytes_ += OS_DOUBLE_PRECISION_FLOATING;
+          break;
+        case OT_SS:
+          // Scalar element of a 128-bit packed single-precision
+          // floating data.
+          // We simply return enItUnknown since we don't have to support
+          // floating point
+          succeeded = false;
+          break;
+        case OT_V:  // Word or doubleword, depending on operand-size attribute.
+          if (operand_is_32_bits_)
+            operand_bytes_ += OS_DOUBLE_WORD;
+          else
+            operand_bytes_ += OS_WORD;
+          break;
+        case OT_W:  // Word, regardless of operand-size attribute.
+          operand_bytes_ += OS_WORD;
+          break;
+
+        // Can safely ignore these.
+        case OT_A:  // Two one-word operands in memory or two double-word
+                    // operands in memory
+        case OT_PI:  // Quadword MMX technology register (e.g. mm0)
+        case OT_SI:  // Doubleword integer register (e.g., eax)
+          break;
+
+        default:
+          break;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  return succeeded;
+}
+
+bool MiniDisassembler::ProcessModrm(unsigned char* start_byte,
+                                    unsigned int* size) {
+  // If we don't need to decode, we just return the size of the ModR/M
+  // byte (there is never a SIB byte in this case).
+  if (!should_decode_modrm_) {
+    (*size)++;
+    return true;
+  }
+
+  // We never care about the reg field, only the combination of the mod
+  // and r/m fields, so let's start by packing those fields together into
+  // 5 bits.
+  unsigned char modrm = (*start_byte);
+  unsigned char mod = modrm & 0xC0;  // mask out top two bits to get mod field
+  modrm = modrm & 0x07;  // mask out bottom 3 bits to get r/m field
+  mod = mod >> 3;  // shift the mod field to the right place
+  modrm = mod | modrm;  // combine the r/m and mod fields as discussed
+  mod = mod >> 3;  // shift the mod field to bits 2..0
+
+  // Invariant: modrm contains the mod field in bits 4..3 and the r/m field
+  // in bits 2..0, and mod contains the mod field in bits 2..0
+
+  const ModrmEntry* modrm_entry = 0;
+  if (address_is_32_bits_)
+    modrm_entry = &s_ia32_modrm_map_[modrm];
+  else
+    modrm_entry = &s_ia16_modrm_map_[modrm];
+
+  // Invariant: modrm_entry points to information that we need to decode
+  // the ModR/M byte.
+
+  // Add to the count of operand bytes, if the ModR/M byte indicates
+  // that some operands are encoded in the instruction.
+  if (modrm_entry->is_encoded_in_instruction_)
+    operand_bytes_ += modrm_entry->operand_size_;
+
+  // Process the SIB byte if necessary, and return the count
+  // of ModR/M and SIB bytes.
+  if (modrm_entry->use_sib_byte_) {
+    (*size)++;
+    return ProcessSib(start_byte + 1, mod, size);
+  } else {
+    (*size)++;
+    return true;
+  }
+}
+
+bool MiniDisassembler::ProcessSib(unsigned char* start_byte,
+                                  unsigned char mod,
+                                  unsigned int* size) {
+  // get the mod field from the 2..0 bits of the SIB byte
+  unsigned char sib_base = (*start_byte) & 0x07;
+  if (0x05 == sib_base) {
+    switch (mod) {
+      case 0x00:  // mod == 00
+      case 0x02:  // mod == 10
+        operand_bytes_ += OS_DOUBLE_WORD;
+        break;
+      case 0x01:  // mod == 01
+        operand_bytes_ += OS_BYTE;
+        break;
+      case 0x03:  // mod == 11
+        // According to the IA-32 docs, there does not seem to be a disp
+        // value for this value of mod
+      default:
+        break;
+    }
+  }
+
+  (*size)++;
+  return true;
+}
+
+};  // namespace sidestep
diff --git a/libchrome/sandbox/win/src/sidestep/mini_disassembler.h b/libchrome/sandbox/win/src/sidestep/mini_disassembler.h
new file mode 100644
index 0000000..202c4ec
--- /dev/null
+++ b/libchrome/sandbox/win/src/sidestep/mini_disassembler.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Definition of MiniDisassembler.
+
+#ifndef SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_H__
+#define SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_H__
+
+#include "sandbox/win/src/sidestep/mini_disassembler_types.h"
+
+namespace sidestep {
+
+// This small disassembler is very limited
+// in its functionality, and in fact does only the bare minimum required by the
+// preamble patching utility.  It may be useful for other purposes, however.
+//
+// The limitations include at least the following:
+//  -# No support for coprocessor opcodes, MMX, etc.
+//  -# No machine-readable identification of opcodes or decoding of
+//     assembly parameters. The name of the opcode (as a string) is given,
+//     however, to aid debugging.
+//
+// You may ask what this little disassembler actually does, then?  The answer is
+// that it does the following, which is exactly what the patching utility needs:
+//  -# Indicates if opcode is a jump (any kind) or a return (any kind)
+//     because this is important for the patching utility to determine if
+//     a function is too short or there are jumps too early in it for it
+//     to be preamble patched.
+//  -# The opcode length is always calculated, so that the patching utility
+//     can figure out where the next instruction starts, and whether it
+//     already has enough instructions to replace with the absolute jump
+//     to the patching code.
+//
+// The usage is quite simple; just create a MiniDisassembler and use its
+// Disassemble() method.
+//
+// If you would like to extend this disassembler, please refer to the
+// IA-32 Intel Architecture Software Developer's Manual Volume 2:
+// Instruction Set Reference for information about operand decoding
+// etc.
+class MiniDisassembler {
+ public:
+
+  // Creates a new instance and sets defaults.
+  //
+  // operand_default_32_bits: If true, the default operand size is
+  // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
+  // address_default_32_bits: If true, the default address size is
+  // set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
+  MiniDisassembler(bool operand_default_32_bits,
+                   bool address_default_32_bits);
+
+  // Equivalent to MiniDisassembler(true, true);
+  MiniDisassembler();
+
+  // Attempts to disassemble a single instruction starting from the
+  // address in memory it is pointed to.
+  //
+  // start: Address where disassembly should start.
+  // instruction_bytes: Variable that will be incremented by
+  // the length in bytes of the instruction.
+  // Returns enItJump, enItReturn or enItGeneric on success.  enItUnknown
+  // if unable to disassemble, enItUnused if this seems to be an unused
+  // opcode. In the last two (error) cases, cbInstruction will be set
+  // to 0xffffffff.
+  //
+  // Postcondition: This instance of the disassembler is ready to be used again,
+  // with unchanged defaults from creation time.
+  InstructionType Disassemble(unsigned char* start,
+                              unsigned int* instruction_bytes);
+
+ private:
+
+  // Makes the disassembler ready for reuse.
+  void Initialize();
+
+  // Sets the flags for address and operand sizes.
+  // Returns Number of prefix bytes.
+  InstructionType ProcessPrefixes(unsigned char* start, unsigned int* size);
+
+  // Sets the flag for whether we have ModR/M, and increments
+  // operand_bytes_ if any are specifies by the opcode directly.
+  // Returns Number of opcode bytes.
+  InstructionType ProcessOpcode(unsigned char* start,
+                                unsigned int table,
+                                unsigned int* size);
+
+  // Checks the type of the supplied operand.  Increments
+  // operand_bytes_ if it directly indicates an immediate etc.
+  // operand.  Asserts have_modrm_ if the operand specifies
+  // a ModR/M byte.
+  bool ProcessOperand(int flag_operand);
+
+  // Increments operand_bytes_ by size specified by ModR/M and
+  // by SIB if present.
+  // Returns 0 in case of error, 1 if there is just a ModR/M byte,
+  // 2 if there is a ModR/M byte and a SIB byte.
+  bool ProcessModrm(unsigned char* start, unsigned int* size);
+
+  // Processes the SIB byte that it is pointed to.
+  // start: Pointer to the SIB byte.
+  // mod: The mod field from the ModR/M byte.
+  // Returns 1 to indicate success (indicates 1 SIB byte)
+  bool ProcessSib(unsigned char* start, unsigned char mod, unsigned int* size);
+
+  // The instruction type we have decoded from the opcode.
+  InstructionType instruction_type_;
+
+  // Counts the number of bytes that is occupied by operands in
+  // the current instruction (note: we don't care about how large
+  // operands stored in registers etc. are).
+  unsigned int operand_bytes_;
+
+  // True iff there is a ModR/M byte in this instruction.
+  bool have_modrm_;
+
+  // True iff we need to decode the ModR/M byte (sometimes it just
+  // points to a register, we can tell by the addressing mode).
+  bool should_decode_modrm_;
+
+  // Current operand size is 32 bits if true, 16 bits if false.
+  bool operand_is_32_bits_;
+
+  // Default operand size is 32 bits if true, 16 bits if false.
+  bool operand_default_is_32_bits_;
+
+  // Current address size is 32 bits if true, 16 bits if false.
+  bool address_is_32_bits_;
+
+  // Default address size is 32 bits if true, 16 bits if false.
+  bool address_default_is_32_bits_;
+
+  // Huge big opcode table based on the IA-32 manual, defined
+  // in Ia32OpcodeMap.cpp
+  static const OpcodeTable s_ia32_opcode_map_[];
+
+  // Somewhat smaller table to help with decoding ModR/M bytes
+  // when 16-bit addressing mode is being used.  Defined in
+  // Ia32ModrmMap.cpp
+  static const ModrmEntry s_ia16_modrm_map_[];
+
+  // Somewhat smaller table to help with decoding ModR/M bytes
+  // when 32-bit addressing mode is being used.  Defined in
+  // Ia32ModrmMap.cpp
+  static const ModrmEntry s_ia32_modrm_map_[];
+
+  // Indicators of whether we got certain prefixes that certain
+  // silly Intel instructions depend on in nonstandard ways for
+  // their behaviors.
+  bool got_f2_prefix_, got_f3_prefix_, got_66_prefix_;
+};
+
+};  // namespace sidestep
+
+#endif  // SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_H__
diff --git a/libchrome/sandbox/win/src/sidestep/mini_disassembler_types.h b/libchrome/sandbox/win/src/sidestep/mini_disassembler_types.h
new file mode 100644
index 0000000..1c10626
--- /dev/null
+++ b/libchrome/sandbox/win/src/sidestep/mini_disassembler_types.h
@@ -0,0 +1,197 @@
+// 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.
+//
+// Several simple types used by the disassembler and some of the patching
+// mechanisms.
+
+#ifndef SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_TYPES_H__
+#define SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_TYPES_H__
+
+namespace sidestep {
+
+// Categories of instructions that we care about
+enum InstructionType {
+  // This opcode is not used
+  IT_UNUSED,
+  // This disassembler does not recognize this opcode (error)
+  IT_UNKNOWN,
+  // This is not an instruction but a reference to another table
+  IT_REFERENCE,
+  // This byte is a prefix byte that we can ignore
+  IT_PREFIX,
+  // This is a prefix byte that switches to the nondefault address size
+  IT_PREFIX_ADDRESS,
+  // This is a prefix byte that switches to the nondefault operand size
+  IT_PREFIX_OPERAND,
+  // A jump or call instruction
+  IT_JUMP,
+  // A return instruction
+  IT_RETURN,
+  // Any other type of instruction (in this case we don't care what it is)
+  IT_GENERIC,
+};
+
+// Lists IA-32 operand sizes in multiples of 8 bits
+enum OperandSize {
+  OS_ZERO = 0,
+  OS_BYTE = 1,
+  OS_WORD = 2,
+  OS_DOUBLE_WORD = 4,
+  OS_QUAD_WORD = 8,
+  OS_DOUBLE_QUAD_WORD = 16,
+  OS_32_BIT_POINTER = 32/8,
+  OS_48_BIT_POINTER = 48/8,
+  OS_SINGLE_PRECISION_FLOATING = 32/8,
+  OS_DOUBLE_PRECISION_FLOATING = 64/8,
+  OS_DOUBLE_EXTENDED_PRECISION_FLOATING = 80/8,
+  OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING = 128/8,
+  OS_PSEUDO_DESCRIPTOR = 6
+};
+
+// Operand addressing methods from the IA-32 manual.  The enAmMask value
+// is a mask for the rest.  The other enumeration values are named for the
+// names given to the addressing methods in the manual, e.g. enAm_D is for
+// the D addressing method.
+//
+// The reason we use a full 4 bytes and a mask, is that we need to combine
+// these flags with the enOperandType to store the details
+// on the operand in a single integer.
+enum AddressingMethod {
+  AM_NOT_USED = 0,        // This operand is not used for this instruction
+  AM_MASK = 0x00FF0000,  // Mask for the rest of the values in this enumeration
+  AM_A = 0x00010000,    // A addressing type
+  AM_C = 0x00020000,    // C addressing type
+  AM_D = 0x00030000,    // D addressing type
+  AM_E = 0x00040000,    // E addressing type
+  AM_F = 0x00050000,    // F addressing type
+  AM_G = 0x00060000,    // G addressing type
+  AM_I = 0x00070000,    // I addressing type
+  AM_J = 0x00080000,    // J addressing type
+  AM_M = 0x00090000,    // M addressing type
+  AM_O = 0x000A0000,    // O addressing type
+  AM_P = 0x000B0000,    // P addressing type
+  AM_Q = 0x000C0000,    // Q addressing type
+  AM_R = 0x000D0000,    // R addressing type
+  AM_S = 0x000E0000,    // S addressing type
+  AM_T = 0x000F0000,    // T addressing type
+  AM_V = 0x00100000,    // V addressing type
+  AM_W = 0x00110000,    // W addressing type
+  AM_X = 0x00120000,    // X addressing type
+  AM_Y = 0x00130000,    // Y addressing type
+  AM_REGISTER = 0x00140000,  // Specific register is always used as this op
+  AM_IMPLICIT = 0x00150000,  // An implicit, fixed value is used
+};
+
+// Operand types from the IA-32 manual. The enOtMask value is
+// a mask for the rest. The rest of the values are named for the
+// names given to these operand types in the manual, e.g. enOt_ps
+// is for the ps operand type in the manual.
+//
+// The reason we use a full 4 bytes and a mask, is that we need
+// to combine these flags with the enAddressingMethod to store the details
+// on the operand in a single integer.
+enum OperandType {
+  OT_MASK = 0xFF000000,
+  OT_A = 0x01000000,
+  OT_B = 0x02000000,
+  OT_C = 0x03000000,
+  OT_D = 0x04000000,
+  OT_DQ = 0x05000000,
+  OT_P = 0x06000000,
+  OT_PI = 0x07000000,
+  OT_PS = 0x08000000,  // actually unsupported for (we don't know its size)
+  OT_Q = 0x09000000,
+  OT_S = 0x0A000000,
+  OT_SS = 0x0B000000,
+  OT_SI = 0x0C000000,
+  OT_V = 0x0D000000,
+  OT_W = 0x0E000000,
+  OT_SD = 0x0F000000,  // scalar double-precision floating-point value
+  OT_PD = 0x10000000,  // double-precision floating point
+  // dummy "operand type" for address mode M - which doesn't specify
+  // operand type
+  OT_ADDRESS_MODE_M = 0x80000000
+};
+
+// Everything that's in an Opcode (see below) except the three
+// alternative opcode structs for different prefixes.
+struct SpecificOpcode {
+  // Index to continuation table, or 0 if this is the last
+  // byte in the opcode.
+  int table_index_;
+
+  // The opcode type
+  InstructionType type_;
+
+  // Description of the type of the dest, src and aux operands,
+  // put together from an enOperandType flag and an enAddressingMethod
+  // flag.
+  int flag_dest_;
+  int flag_source_;
+  int flag_aux_;
+
+  // We indicate the mnemonic for debugging purposes
+  const char* mnemonic_;
+};
+
+// The information we keep in our tables about each of the different
+// valid instructions recognized by the IA-32 architecture.
+struct Opcode {
+  // Index to continuation table, or 0 if this is the last
+  // byte in the opcode.
+  int table_index_;
+
+  // The opcode type
+  InstructionType type_;
+
+  // Description of the type of the dest, src and aux operands,
+  // put together from an enOperandType flag and an enAddressingMethod
+  // flag.
+  int flag_dest_;
+  int flag_source_;
+  int flag_aux_;
+
+  // We indicate the mnemonic for debugging purposes
+  const char* mnemonic_;
+
+  // Alternative opcode info if certain prefixes are specified.
+  // In most cases, all of these are zeroed-out.  Only used if
+  // bPrefixDependent is true.
+  bool is_prefix_dependent_;
+  SpecificOpcode opcode_if_f2_prefix_;
+  SpecificOpcode opcode_if_f3_prefix_;
+  SpecificOpcode opcode_if_66_prefix_;
+};
+
+// Information about each table entry.
+struct OpcodeTable {
+  // Table of instruction entries
+  const Opcode* table_;
+  // How many bytes left to shift ModR/M byte <b>before</b> applying mask
+  unsigned char shift_;
+  // Mask to apply to byte being looked at before comparing to table
+  unsigned char mask_;
+  // Minimum/maximum indexes in table.
+  unsigned char min_lim_;
+  unsigned char max_lim_;
+};
+
+// Information about each entry in table used to decode ModR/M byte.
+struct ModrmEntry {
+  // Is the operand encoded as bytes in the instruction (rather than
+  // if it's e.g. a register in which case it's just encoded in the
+  // ModR/M byte)
+  bool is_encoded_in_instruction_;
+
+  // Is there a SIB byte?  In this case we always need to decode it.
+  bool use_sib_byte_;
+
+  // What is the size of the operand (only important if it's encoded
+  // in the instruction)?
+  OperandSize operand_size_;
+};
+
+};  // namespace sidestep
+
+#endif  // SANDBOX_SRC_SIDESTEP_MINI_DISASSEMBLER_TYPES_H__
diff --git a/libchrome/sandbox/win/src/sidestep/preamble_patcher.h b/libchrome/sandbox/win/src/sidestep/preamble_patcher.h
new file mode 100644
index 0000000..3a0985c
--- /dev/null
+++ b/libchrome/sandbox/win/src/sidestep/preamble_patcher.h
@@ -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.
+
+// Definition of PreamblePatcher
+
+#ifndef SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
+#define SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
+
+#include <stddef.h>
+
+namespace sidestep {
+
+// Maximum size of the preamble stub. We overwrite at least the first 5
+// bytes of the function. Considering the worst case scenario, we need 4
+// bytes + the max instruction size + 5 more bytes for our jump back to
+// the original code. With that in mind, 32 is a good number :)
+const size_t kMaxPreambleStubSize = 32;
+
+// Possible results of patching/unpatching
+enum SideStepError {
+  SIDESTEP_SUCCESS = 0,
+  SIDESTEP_INVALID_PARAMETER,
+  SIDESTEP_INSUFFICIENT_BUFFER,
+  SIDESTEP_JUMP_INSTRUCTION,
+  SIDESTEP_FUNCTION_TOO_SMALL,
+  SIDESTEP_UNSUPPORTED_INSTRUCTION,
+  SIDESTEP_NO_SUCH_MODULE,
+  SIDESTEP_NO_SUCH_FUNCTION,
+  SIDESTEP_ACCESS_DENIED,
+  SIDESTEP_UNEXPECTED,
+};
+
+// Implements a patching mechanism that overwrites the first few bytes of
+// a function preamble with a jump to our hook function, which is then
+// able to call the original function via a specially-made preamble-stub
+// that imitates the action of the original preamble.
+//
+// Note that there are a number of ways that this method of patching can
+// fail.  The most common are:
+//    - If there is a jump (jxx) instruction in the first 5 bytes of
+//    the function being patched, we cannot patch it because in the
+//    current implementation we do not know how to rewrite relative
+//    jumps after relocating them to the preamble-stub.  Note that
+//    if you really really need to patch a function like this, it
+//    would be possible to add this functionality (but at some cost).
+//    - If there is a return (ret) instruction in the first 5 bytes
+//    we cannot patch the function because it may not be long enough
+//    for the jmp instruction we use to inject our patch.
+//    - If there is another thread currently executing within the bytes
+//    that are copied to the preamble stub, it will crash in an undefined
+//    way.
+//
+// If you get any other error than the above, you're either pointing the
+// patcher at an invalid instruction (e.g. into the middle of a multi-
+// byte instruction, or not at memory containing executable instructions)
+// or, there may be a bug in the disassembler we use to find
+// instruction boundaries.
+class PreamblePatcher {
+ public:
+  // Patches target_function to point to replacement_function using a provided
+  // preamble_stub of stub_size bytes.
+  // Returns An error code indicating the result of patching.
+  template <class T>
+  static SideStepError Patch(T target_function, T replacement_function,
+                             void* preamble_stub, size_t stub_size) {
+    return RawPatchWithStub(target_function, replacement_function,
+                            reinterpret_cast<unsigned char*>(preamble_stub),
+                            stub_size, NULL);
+  }
+
+ private:
+
+  // Patches a function by overwriting its first few bytes with
+  // a jump to a different function.  This is similar to the RawPatch
+  // function except that it uses the stub allocated by the caller
+  // instead of allocating it.
+  //
+  // To use this function, you first have to call VirtualProtect to make the
+  // target function writable at least for the duration of the call.
+  //
+  // target_function: A pointer to the function that should be
+  // patched.
+  //
+  // replacement_function: A pointer to the function that should
+  // replace the target function.  The replacement function must have
+  // exactly the same calling convention and parameters as the original
+  // function.
+  //
+  // preamble_stub: A pointer to a buffer where the preamble stub
+  // should be copied. The size of the buffer should be sufficient to
+  // hold the preamble bytes.
+  //
+  // stub_size: Size in bytes of the buffer allocated for the
+  // preamble_stub
+  //
+  // bytes_needed: Pointer to a variable that receives the minimum
+  // number of bytes required for the stub.  Can be set to NULL if you're
+  // not interested.
+  //
+  // Returns An error code indicating the result of patching.
+  static SideStepError RawPatchWithStub(void* target_function,
+                                        void *replacement_function,
+                                        unsigned char* preamble_stub,
+                                        size_t stub_size,
+                                        size_t* bytes_needed);
+};
+
+};  // namespace sidestep
+
+#endif  // SANDBOX_SRC_SIDESTEP_PREAMBLE_PATCHER_H__
diff --git a/libchrome/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp b/libchrome/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
new file mode 100644
index 0000000..b501600
--- /dev/null
+++ b/libchrome/sandbox/win/src/sidestep/preamble_patcher_with_stub.cpp
@@ -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.
+
+// Implementation of PreamblePatcher
+
+#include "sandbox/win/src/sidestep/preamble_patcher.h"
+
+#include <stddef.h>
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sidestep/mini_disassembler.h"
+
+// Definitions of assembly statements we need
+#define ASM_JMP32REL 0xE9
+#define ASM_INT3 0xCC
+
+namespace {
+
+// Very basic memcpy. We are copying 4 to 12 bytes most of the time, so there
+// is no attempt to optimize this code or have a general purpose function.
+// We don't want to call the crt from this code.
+inline void* RawMemcpy(void* destination, const void* source, size_t bytes) {
+  const char* from = reinterpret_cast<const char*>(source);
+  char* to = reinterpret_cast<char*>(destination);
+
+  for (size_t i = 0; i < bytes ; i++)
+    to[i] = from[i];
+
+  return destination;
+}
+
+// Very basic memset. We are filling 1 to 7 bytes most of the time, so there
+// is no attempt to optimize this code or have a general purpose function.
+// We don't want to call the crt from this code.
+inline void* RawMemset(void* destination, int value, size_t bytes) {
+  char* to = reinterpret_cast<char*>(destination);
+
+  for (size_t i = 0; i < bytes ; i++)
+    to[i] = static_cast<char>(value);
+
+  return destination;
+}
+
+}  // namespace
+
+#define ASSERT(a, b) DCHECK_NT(a)
+
+namespace sidestep {
+
+SideStepError PreamblePatcher::RawPatchWithStub(
+    void* target_function,
+    void* replacement_function,
+    unsigned char* preamble_stub,
+    size_t stub_size,
+    size_t* bytes_needed) {
+  if ((NULL == target_function) ||
+      (NULL == replacement_function) ||
+      (NULL == preamble_stub)) {
+    ASSERT(false, (L"Invalid parameters - either pTargetFunction or "
+                   L"pReplacementFunction or pPreambleStub were NULL."));
+    return SIDESTEP_INVALID_PARAMETER;
+  }
+
+  // TODO(V7:joi) Siggi and I just had a discussion and decided that both
+  // patching and unpatching are actually unsafe.  We also discussed a
+  // method of making it safe, which is to freeze all other threads in the
+  // process, check their thread context to see if their eip is currently
+  // inside the block of instructions we need to copy to the stub, and if so
+  // wait a bit and try again, then unfreeze all threads once we've patched.
+  // Not implementing this for now since we're only using SideStep for unit
+  // testing, but if we ever use it for production code this is what we
+  // should do.
+  //
+  // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using
+  // FPU instructions, and on newer processors we could use cmpxchg8b or
+  // cmpxchg16b. So it might be possible to do the patching/unpatching
+  // atomically and avoid having to freeze other threads.  Note though, that
+  // doing it atomically does not help if one of the other threads happens
+  // to have its eip in the middle of the bytes you change while you change
+  // them.
+  unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
+
+  // Let's disassemble the preamble of the target function to see if we can
+  // patch, and to see how much of the preamble we need to take.  We need 5
+  // bytes for our jmp instruction, so let's find the minimum number of
+  // instructions to get 5 bytes.
+  MiniDisassembler disassembler;
+  unsigned int preamble_bytes = 0;
+  while (preamble_bytes < 5) {
+    InstructionType instruction_type =
+      disassembler.Disassemble(target + preamble_bytes, &preamble_bytes);
+    if (IT_JUMP == instruction_type) {
+      ASSERT(false, (L"Unable to patch because there is a jump instruction "
+                     L"in the first 5 bytes."));
+      return SIDESTEP_JUMP_INSTRUCTION;
+    } else if (IT_RETURN == instruction_type) {
+      ASSERT(false, (L"Unable to patch because function is too short"));
+      return SIDESTEP_FUNCTION_TOO_SMALL;
+    } else if (IT_GENERIC != instruction_type) {
+      ASSERT(false, (L"Disassembler encountered unsupported instruction "
+                     L"(either unused or unknown"));
+      return SIDESTEP_UNSUPPORTED_INSTRUCTION;
+    }
+  }
+
+  if (NULL != bytes_needed)
+    *bytes_needed = preamble_bytes + 5;
+
+  // Inv: preamble_bytes is the number of bytes (at least 5) that we need to
+  // take from the preamble to have whole instructions that are 5 bytes or more
+  // in size total. The size of the stub required is cbPreamble + size of
+  // jmp (5)
+  if (preamble_bytes + 5 > stub_size) {
+    NOTREACHED_NT();
+    return SIDESTEP_INSUFFICIENT_BUFFER;
+  }
+
+  // First, copy the preamble that we will overwrite.
+  RawMemcpy(reinterpret_cast<void*>(preamble_stub),
+            reinterpret_cast<void*>(target), preamble_bytes);
+
+  // Now, make a jmp instruction to the rest of the target function (minus the
+  // preamble bytes we moved into the stub) and copy it into our preamble-stub.
+  // find address to jump to, relative to next address after jmp instruction
+#pragma warning(push)
+#pragma warning(disable:4244)
+  // This assignment generates a warning because it is 32 bit specific.
+  int relative_offset_to_target_rest
+    = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) -
+        (preamble_stub + preamble_bytes + 5));
+#pragma warning(pop)
+  // jmp (Jump near, relative, displacement relative to next instruction)
+  preamble_stub[preamble_bytes] = ASM_JMP32REL;
+  // copy the address
+  RawMemcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1),
+            reinterpret_cast<void*>(&relative_offset_to_target_rest), 4);
+
+  // Inv: preamble_stub points to assembly code that will execute the
+  // original function by first executing the first cbPreamble bytes of the
+  // preamble, then jumping to the rest of the function.
+
+  // Overwrite the first 5 bytes of the target function with a jump to our
+  // replacement function.
+  // (Jump near, relative, displacement relative to next instruction)
+  target[0] = ASM_JMP32REL;
+
+  // Find offset from instruction after jmp, to the replacement function.
+#pragma warning(push)
+#pragma warning(disable:4244)
+  int offset_to_replacement_function =
+    reinterpret_cast<unsigned char*>(replacement_function) -
+    reinterpret_cast<unsigned char*>(target) - 5;
+#pragma warning(pop)
+  // complete the jmp instruction
+  RawMemcpy(reinterpret_cast<void*>(target + 1),
+            reinterpret_cast<void*>(&offset_to_replacement_function), 4);
+  // Set any remaining bytes that were moved to the preamble-stub to INT3 so
+  // as not to cause confusion (otherwise you might see some strange
+  // instructions if you look at the disassembly, or even invalid
+  // instructions). Also, by doing this, we will break into the debugger if
+  // some code calls into this portion of the code.  If this happens, it
+  // means that this function cannot be patched using this patcher without
+  // further thought.
+  if (preamble_bytes > 5) {
+    RawMemset(reinterpret_cast<void*>(target + 5), ASM_INT3,
+              preamble_bytes - 5);
+  }
+
+  // Inv: The memory pointed to by target_function now points to a relative
+  // jump instruction that jumps over to the preamble_stub.  The preamble
+  // stub contains the first stub_size bytes of the original target
+  // function's preamble code, followed by a relative jump back to the next
+  // instruction after the first cbPreamble bytes.
+
+  return SIDESTEP_SUCCESS;
+}
+
+};  // namespace sidestep
+
+#undef ASSERT
diff --git a/libchrome/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj b/libchrome/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj
new file mode 100644
index 0000000..53816e7
--- /dev/null
+++ b/libchrome/sandbox/win/tests/integration_tests/sbox_integration_tests.vcproj
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sbox_integration_tests"
+	ProjectGUID="{542D4B3B-98D4-4233-B68D-0103891508C6}"
+	RootNamespace="unit_tests"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="0"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/safeseh /dynamicbase /ignore:4199 $(NoInherit)"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Common"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{49F2D231-E141-4455-B241-7D37C09B6EEB}"
+			>
+			<File
+				RelativePath="..\common\controller.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\common\controller.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\integration_tests.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\stdafx.h"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath="..\..\src\dep_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\file_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\integration_tests_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\integrity_level_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\ipc_ping_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\named_pipe_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\policy_target_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\process_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\registry_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\sync_policy_test.cc"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\unload_dll_test.cc"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/tests/unit_tests/sbox_unittests.vcproj b/libchrome/sandbox/win/tests/unit_tests/sbox_unittests.vcproj
new file mode 100644
index 0000000..a2df792
--- /dev/null
+++ b/libchrome/sandbox/win/tests/unit_tests/sbox_unittests.vcproj
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sbox_unittests"
+	ProjectGUID="{883553BE-2A9D-418C-A121-61FE1DFBC562}"
+	RootNamespace="unit_tests"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Common"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="0"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\stdafx.h"
+				>
+			</File>
+			<File
+				RelativePath=".\unit_tests.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="TestInterception"
+			>
+			<File
+				RelativePath="..\..\src\interception_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\pe_image_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\service_resolver_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="TestRestrictedToken"
+			>
+			<File
+				RelativePath="..\..\src\restricted_token_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="TestJob"
+			>
+			<File
+				RelativePath="..\..\src\job_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Sid"
+			>
+			<File
+				RelativePath="..\..\src\sid_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Policy"
+			>
+			<File
+				RelativePath="..\..\src\policy_engine_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\policy_low_level_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\policy_opcodes_unittest.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="IPC"
+			>
+			<File
+				RelativePath="..\..\src\ipc_unittest.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\threadpool_unittest.cc"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj b/libchrome/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj
new file mode 100644
index 0000000..9b7b599
--- /dev/null
+++ b/libchrome/sandbox/win/tests/validation_tests/sbox_validation_tests.vcproj
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sbox_validation_tests"
+	ProjectGUID="{B9CC7B0D-145A-49C2-B887-84E43CFA0F27}"
+	RootNamespace="unit_tests"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="2"
+				WarningLevel="3"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="shlwapi.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="_CONSOLE"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="shlwapi.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Common"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{2E6C7E35-7538-4883-B80C-C89961A80D66}"
+			>
+			<File
+				RelativePath="..\common\controller.cc"
+				>
+			</File>
+			<File
+				RelativePath="..\common\controller.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\testing\gtest\src\gtest.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\stdafx.cc"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath=".\stdafx.h"
+				>
+			</File>
+			<File
+				RelativePath=".\unit_tests.cc"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Suite"
+			>
+			<File
+				RelativePath=".\commands.cc"
+				>
+			</File>
+			<File
+				RelativePath=".\commands.h"
+				>
+			</File>
+			<File
+				RelativePath=".\suite.cc"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/tools/finder/finder.vcproj b/libchrome/sandbox/win/tools/finder/finder.vcproj
new file mode 100644
index 0000000..787c847
--- /dev/null
+++ b/libchrome/sandbox/win/tools/finder/finder.vcproj
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="finder"
+	ProjectGUID="{ACDC2E06-0366-41A4-A646-C37E130A605D}"
+	RootNamespace="finder"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\finder.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\finder.h"
+			>
+		</File>
+		<File
+			RelativePath=".\finder_fs.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\finder_kernel.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\finder_registry.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\main.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\ntundoc.h"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/tools/finder/ntundoc.h b/libchrome/sandbox/win/tools/finder/ntundoc.h
new file mode 100644
index 0000000..dc8c3a5
--- /dev/null
+++ b/libchrome/sandbox/win/tools/finder/ntundoc.h
@@ -0,0 +1,275 @@
+// Copyright (c) 2006-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 SANDBOX_TOOLS_FINDER_NTUNDOC_H__
+#define SANDBOX_TOOLS_FINDER_NTUNDOC_H__
+
+#define NTSTATUS ULONG
+#define STATUS_SUCCESS 0x00000000
+#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
+#define STATUS_ACCESS_DENIED 0xC0000022
+#define STATUS_BUFFER_OVERFLOW 0x80000005
+
+typedef struct _LSA_UNICODE_STRING {
+  USHORT Length;
+  USHORT MaximumLength;
+  PWSTR Buffer;
+} UNICODE_STRING;
+
+typedef struct _OBJDIR_INFORMATION {
+  UNICODE_STRING ObjectName;
+  UNICODE_STRING ObjectTypeName;
+  BYTE Data[1];
+} OBJDIR_INFORMATION;
+
+typedef struct _OBJECT_ATTRIBUTES {
+  ULONG Length;
+  HANDLE RootDirectory;
+  UNICODE_STRING *ObjectName;
+  ULONG Attributes;
+  PVOID SecurityDescriptor;
+  PVOID SecurityQualityOfService;
+} OBJECT_ATTRIBUTES;
+
+typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
+  ULONG Attributes;
+  ACCESS_MASK GrantedAccess;
+  ULONG HandleCount;
+  ULONG PointerCount;
+  ULONG Reserved[10];    // reserved for internal use
+ } PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION;
+
+typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING TypeName;
+  ULONG Reserved [22];    // reserved for internal use
+} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;
+
+typedef enum _POOL_TYPE {
+  NonPagedPool,
+  PagedPool,
+  NonPagedPoolMustSucceed,
+  ReservedType,
+  NonPagedPoolCacheAligned,
+  PagedPoolCacheAligned,
+  NonPagedPoolCacheAlignedMustS
+} POOL_TYPE;
+
+typedef struct _OBJECT_TYPE_INFORMATION {
+  UNICODE_STRING Name;
+  ULONG TotalNumberOfObjects;
+  ULONG TotalNumberOfHandles;
+  ULONG TotalPagedPoolUsage;
+  ULONG TotalNonPagedPoolUsage;
+  ULONG TotalNamePoolUsage;
+  ULONG TotalHandleTableUsage;
+  ULONG HighWaterNumberOfObjects;
+  ULONG HighWaterNumberOfHandles;
+  ULONG HighWaterPagedPoolUsage;
+  ULONG HighWaterNonPagedPoolUsage;
+  ULONG HighWaterNamePoolUsage;
+  ULONG HighWaterHandleTableUsage;
+  ULONG InvalidAttributes;
+  GENERIC_MAPPING GenericMapping;
+  ULONG ValidAccess;
+  BOOLEAN SecurityRequired;
+  BOOLEAN MaintainHandleCount;
+  USHORT MaintainTypeList;
+  POOL_TYPE PoolType;
+  ULONG PagedPoolUsage;
+  ULONG NonPagedPoolUsage;
+} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+
+typedef struct _OBJECT_NAME_INFORMATION {
+  UNICODE_STRING          ObjectName;
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef enum _OBJECT_INFORMATION_CLASS {
+  ObjectBasicInformation,
+  ObjectNameInformation,
+  ObjectTypeInformation,
+  ObjectAllInformation,
+  ObjectDataInformation
+} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
+
+typedef struct _FILE_NAME_INFORMATION {
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ // end_wdm
+  FileDirectoryInformation       = 1,
+  FileFullDirectoryInformation, // 2
+  FileBothDirectoryInformation, // 3
+  FileBasicInformation,         // 4  wdm
+  FileStandardInformation,      // 5  wdm
+  FileInternalInformation,      // 6
+  FileEaInformation,            // 7
+  FileAccessInformation,        // 8
+  FileNameInformation,          // 9
+  FileRenameInformation,        // 10
+  FileLinkInformation,          // 11
+  FileNamesInformation,         // 12
+  FileDispositionInformation,   // 13
+  FilePositionInformation,      // 14 wdm
+  FileFullEaInformation,        // 15
+  FileModeInformation,          // 16
+  FileAlignmentInformation,     // 17
+  FileAllInformation,           // 18
+  FileAllocationInformation,    // 19
+  FileEndOfFileInformation,     // 20 wdm
+  FileAlternateNameInformation, // 21
+  FileStreamInformation,        // 22
+  FilePipeInformation,          // 23
+  FilePipeLocalInformation,     // 24
+  FilePipeRemoteInformation,    // 25
+  FileMailslotQueryInformation, // 26
+  FileMailslotSetInformation,   // 27
+  FileCompressionInformation,   // 28
+  FileObjectIdInformation,      // 29
+  FileCompletionInformation,    // 30
+  FileMoveClusterInformation,   // 31
+  FileQuotaInformation,         // 32
+  FileReparsePointInformation,  // 33
+  FileNetworkOpenInformation,   // 34
+  FileAttributeTagInformation,  // 35
+  FileTrackingInformation,      // 36
+  FileMaximumInformation
+  // begin_wdm
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+  SystemHandleInformation = 16
+} SYSTEM_INFORMATION_CLASS;
+
+typedef struct _IO_STATUS_BLOCK {
+    union {
+        NTSTATUS Status;
+        PVOID Pointer;
+    };
+    ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+#define InitializeObjectAttributes( p, n, a, r, s ) { \
+    (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
+    (p)->RootDirectory = r; \
+    (p)->Attributes = a; \
+    (p)->ObjectName = n; \
+    (p)->SecurityDescriptor = s; \
+    (p)->SecurityQualityOfService = NULL; \
+}
+
+typedef struct _SYSTEM_HANDLE_INFORMATION {
+  USHORT ProcessId;
+  USHORT CreatorBackTraceIndex;
+  UCHAR ObjectTypeNumber;
+  UCHAR Flags;
+  USHORT Handle;
+  PVOID Object;
+  ACCESS_MASK GrantedAccess;
+} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+  ULONG NumberOfHandles;
+  SYSTEM_HANDLE_INFORMATION Information[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
+#define POBJECT_ATTRIBUTES OBJECT_ATTRIBUTES*
+
+typedef NTSTATUS (WINAPI* NTQUERYDIRECTORYOBJECT)(
+  HANDLE,
+  OBJDIR_INFORMATION*,
+  DWORD,
+  DWORD,
+  DWORD,
+  DWORD*,
+  DWORD*);
+
+typedef NTSTATUS (WINAPI* NTOPENDIRECTORYOBJECT)(
+  HANDLE *,
+  DWORD,
+  OBJECT_ATTRIBUTES* );
+
+typedef NTSTATUS (WINAPI* NTGENERICOPEN) (
+  OUT PHANDLE EventHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENEVENT)(
+  OUT PHANDLE EventHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENJOBOBJECT)(
+  OUT PHANDLE JobHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENKEYEDEVENT)(
+  OUT PHANDLE KeyedEventHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENMUTANT)(
+  OUT PHANDLE MutantHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENSECTION)(
+  OUT PHANDLE SectionHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENSEMAPHORE)(
+  OUT PHANDLE SemaphoreHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENSYMBOLICLINKOBJECT)(
+  OUT PHANDLE SymbolicLinkHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENTIMER)(
+  OUT PHANDLE TimerHandle,
+  IN ACCESS_MASK DesiredAccess,
+  IN POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS (WINAPI* NTOPENFILE)(
+  HANDLE *,
+  DWORD,
+  OBJECT_ATTRIBUTES *,
+  IO_STATUS_BLOCK *,
+  DWORD,
+  DWORD);
+
+typedef NTSTATUS (WINAPI* NTQUERYINFORMATIONFILE)(
+  HANDLE,
+  PIO_STATUS_BLOCK,
+  PVOID,
+  ULONG,
+  FILE_INFORMATION_CLASS);
+
+typedef NTSTATUS (WINAPI* NTQUERYSYSTEMINFORMATION)(
+  SYSTEM_INFORMATION_CLASS SystemInformationClass,
+  PVOID SystemInformation,
+  ULONG SystemInformationLength,
+  PULONG ReturnLength);
+
+typedef NTSTATUS (WINAPI* NTQUERYOBJECT)(
+  HANDLE Handle,
+  OBJECT_INFORMATION_CLASS ObjectInformationClass,
+  PVOID ObjectInformation,
+  ULONG ObjectInformationLength,
+  PULONG ReturnLength);
+
+typedef NTSTATUS (WINAPI* NTCLOSE) (HANDLE);
+
+#define DIRECTORY_QUERY 0x0001
+#define DIRECTORY_TRAVERSE 0x0002
+#define DIRECTORY_CREATE_OBJECT 0x0004
+#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
+#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF)
+
+#endif  // SANDBOX_TOOLS_FINDER_NTUNDOC_H__
diff --git a/libchrome/sandbox/win/tools/launcher/launcher.vcproj b/libchrome/sandbox/win/tools/launcher/launcher.vcproj
new file mode 100644
index 0000000..71ed011
--- /dev/null
+++ b/libchrome/sandbox/win/tools/launcher/launcher.vcproj
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="launcher"
+	ProjectGUID="{386FA217-FBC2-4461-882D-CDAD221ED800}"
+	RootNamespace="launcher"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="2"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				UsePrecompiledHeader="0"
+				ForcedIncludeFiles="stdafx.h"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<File
+			RelativePath=".\launcher.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\stdafx.cc"
+			>
+			<FileConfiguration
+				Name="Debug|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="1"
+				/>
+			</FileConfiguration>
+			<FileConfiguration
+				Name="Release|Win32"
+				>
+				<Tool
+					Name="VCCLCompilerTool"
+					UsePrecompiledHeader="0"
+				/>
+			</FileConfiguration>
+		</File>
+		<File
+			RelativePath=".\stdafx.h"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/sandbox/win/wow_helper.sln b/libchrome/sandbox/win/wow_helper.sln
new file mode 100644
index 0000000..26d0da2
--- /dev/null
+++ b/libchrome/sandbox/win/wow_helper.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wow_helper", "wow_helper\wow_helper.vcproj", "{BCF3A457-39F1-4DAA-9A65-93CFCD559036}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Debug|x64.ActiveCfg = Debug|x64
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Debug|x64.Build.0 = Debug|x64
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Release|x64.ActiveCfg = Release|x64
+		{BCF3A457-39F1-4DAA-9A65-93CFCD559036}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/libchrome/sandbox/win/wow_helper/wow_helper.exe b/libchrome/sandbox/win/wow_helper/wow_helper.exe
new file mode 100755
index 0000000..f9bfb4b
--- /dev/null
+++ b/libchrome/sandbox/win/wow_helper/wow_helper.exe
Binary files differ
diff --git a/libchrome/sandbox/win/wow_helper/wow_helper.pdb b/libchrome/sandbox/win/wow_helper/wow_helper.pdb
new file mode 100644
index 0000000..9cb67d0
--- /dev/null
+++ b/libchrome/sandbox/win/wow_helper/wow_helper.pdb
Binary files differ
diff --git a/libchrome/sandbox/win/wow_helper/wow_helper.vcproj b/libchrome/sandbox/win/wow_helper/wow_helper.vcproj
new file mode 100644
index 0000000..c8e7c9e
--- /dev/null
+++ b/libchrome/sandbox/win/wow_helper/wow_helper.vcproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="wow_helper"
+	ProjectGUID="{BCF3A457-39F1-4DAA-9A65-93CFCD559036}"
+	RootNamespace="wow_helper"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="x64"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|x64"
+			OutputDirectory="$(ProjectDir)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="$(SolutionDir)..;$(SolutionDir)..\third_party\platformsdk_win2008_6_1\files\Include;$(VSInstallDir)\VC\atlmfc\include"
+				PreprocessorDefinitions="_WIN32_WINNT=0x0501;WINVER=0x0501;WIN32;_DEBUG"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="0"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|x64"
+			OutputDirectory="$(ProjectDir)"
+			IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+				TargetEnvironment="3"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="$(SolutionDir)..;$(SolutionDir)..\third_party\platformsdk_win2008_6_1\files\Include;$(VSInstallDir)\VC\atlmfc\include"
+				PreprocessorDefinitions="_WIN32_WINNT=0x0501;WINVER=0x0501;WIN32;NDEBUG"
+				RuntimeLibrary="0"
+				BufferSecurityCheck="false"
+				RuntimeTypeInfo="false"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="17"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="sandbox"
+			>
+			<File
+				RelativePath="..\src\nt_internals.h"
+				>
+			</File>
+			<File
+				RelativePath="..\src\resolver.h"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath=".\service64_resolver.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\service64_resolver.h"
+			>
+		</File>
+		<File
+			RelativePath=".\target_code.cc"
+			>
+		</File>
+		<File
+			RelativePath=".\target_code.h"
+			>
+		</File>
+		<File
+			RelativePath=".\wow_helper.cc"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/libchrome/testing/gmock/include/gmock/gmock.h b/libchrome/testing/gmock/include/gmock/gmock.h
new file mode 100644
index 0000000..9678b68
--- /dev/null
+++ b/libchrome/testing/gmock/include/gmock/gmock.h
@@ -0,0 +1 @@
+#include <gmock/gmock.h>
diff --git a/libchrome/testing/gtest/include/gtest/gtest.h b/libchrome/testing/gtest/include/gtest/gtest.h
new file mode 100644
index 0000000..2180533
--- /dev/null
+++ b/libchrome/testing/gtest/include/gtest/gtest.h
@@ -0,0 +1 @@
+#include <gtest/gtest.h>
diff --git a/libchrome/testing/gtest/include/gtest/gtest_prod.h b/libchrome/testing/gtest/include/gtest/gtest_prod.h
new file mode 100644
index 0000000..00174fc
--- /dev/null
+++ b/libchrome/testing/gtest/include/gtest/gtest_prod.h
@@ -0,0 +1 @@
+#include <gtest/gtest_prod.h>
diff --git a/libchrome/testing/multiprocess_func_list.cc b/libchrome/testing/multiprocess_func_list.cc
new file mode 100644
index 0000000..f96c2b5
--- /dev/null
+++ b/libchrome/testing/multiprocess_func_list.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 "multiprocess_func_list.h"
+
+#include <map>
+
+// Helper functions to maintain mapping of "test name"->test func.
+// The information is accessed via a global map.
+namespace multi_process_function_list {
+
+namespace {
+
+struct ProcessFunctions {
+  ProcessFunctions() : main(NULL), setup(NULL) {}
+  ProcessFunctions(TestMainFunctionPtr main, SetupFunctionPtr setup)
+      : main(main),
+        setup(setup) {
+  }
+  TestMainFunctionPtr main;
+  SetupFunctionPtr setup;
+};
+
+typedef std::map<std::string, ProcessFunctions> MultiProcessTestMap;
+
+// Retrieve a reference to the global 'func name' -> func ptr map.
+MultiProcessTestMap& GetMultiprocessFuncMap() {
+  static MultiProcessTestMap test_name_to_func_ptr_map;
+  return test_name_to_func_ptr_map;
+}
+
+}  // namespace
+
+AppendMultiProcessTest::AppendMultiProcessTest(
+    std::string test_name,
+    TestMainFunctionPtr main_func_ptr,
+    SetupFunctionPtr setup_func_ptr) {
+  GetMultiprocessFuncMap()[test_name] =
+      ProcessFunctions(main_func_ptr, setup_func_ptr);
+}
+
+int InvokeChildProcessTest(const std::string& test_name) {
+  MultiProcessTestMap& func_lookup_table = GetMultiprocessFuncMap();
+  MultiProcessTestMap::iterator it = func_lookup_table.find(test_name);
+  if (it != func_lookup_table.end()) {
+    const ProcessFunctions& process_functions = it->second;
+    if (process_functions.setup)
+      (*process_functions.setup)();
+    if (process_functions.main)
+      return (*process_functions.main)();
+  }
+
+  return -1;
+}
+
+}  // namespace multi_process_function_list
diff --git a/libchrome/testing/multiprocess_func_list.h b/libchrome/testing/multiprocess_func_list.h
new file mode 100644
index 0000000..c3d2f1f
--- /dev/null
+++ b/libchrome/testing/multiprocess_func_list.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TESTING_MULTIPROCESS_FUNC_LIST_H_
+#define TESTING_MULTIPROCESS_FUNC_LIST_H_
+
+#include <string>
+
+// This file provides the plumbing to register functions to be executed
+// as the main function of a child process in a multi-process test.
+// This complements the MultiProcessTest class which provides facilities
+// for launching such tests.
+//
+// The MULTIPROCESS_TEST_MAIN() macro registers a string -> func_ptr mapping
+// by creating a new global instance of the AppendMultiProcessTest() class
+// this means that by the time that we reach our main() function the mapping
+// is already in place.
+//
+// Example usage:
+//  MULTIPROCESS_TEST_MAIN(a_test_func) {
+//    // Code here runs in a child process.
+//    return 0;
+//  }
+//
+// The prototype of a_test_func is implicitly
+//   int test_main_func_name();
+
+namespace multi_process_function_list {
+
+// Type for child process main functions.
+typedef int (*TestMainFunctionPtr)();
+
+// Type for child setup functions.
+typedef void (*SetupFunctionPtr)();
+
+// Helper class to append a test function to the global mapping.
+// Used by the MULTIPROCESS_TEST_MAIN macro.
+class AppendMultiProcessTest {
+ public:
+  // |main_func_ptr| is the main function that is run in the child process.
+  // |setup_func_ptr| is a function run when the global mapping is added.
+  AppendMultiProcessTest(std::string test_name,
+                         TestMainFunctionPtr main_func_ptr,
+                         SetupFunctionPtr setup_func_ptr);
+};
+
+// Invoke the main function of a test previously registered with
+// MULTIPROCESS_TEST_MAIN()
+int InvokeChildProcessTest(const std::string& test_name);
+
+// This macro creates a global MultiProcessTest::AppendMultiProcessTest object
+// whose constructor does the work of adding the global mapping.
+#define MULTIPROCESS_TEST_MAIN(test_main) \
+  MULTIPROCESS_TEST_MAIN_WITH_SETUP(test_main, NULL)
+
+// Same as above but lets callers specify a setup method that is run in the
+// child process, just before the main function is run.  This facilitates
+// adding a generic one-time setup function for multiple tests.
+#define MULTIPROCESS_TEST_MAIN_WITH_SETUP(test_main, test_setup) \
+  int test_main(); \
+  namespace { \
+    multi_process_function_list::AppendMultiProcessTest \
+    AddMultiProcessTest##_##test_main(#test_main, (test_main), (test_setup)); \
+  } \
+  int test_main()
+
+}  // namespace multi_process_function_list
+
+#endif  // TESTING_MULTIPROCESS_FUNC_LIST_H_
diff --git a/libchrome/testing/platform_test.h b/libchrome/testing/platform_test.h
new file mode 100644
index 0000000..04fc845
--- /dev/null
+++ b/libchrome/testing/platform_test.h
@@ -0,0 +1,36 @@
+// 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 TESTING_PLATFORM_TEST_H_
+#define TESTING_PLATFORM_TEST_H_
+
+#include <gtest/gtest.h>
+
+#if defined(GTEST_OS_MAC)
+#ifdef __OBJC__
+@class NSAutoreleasePool;
+#else
+class NSAutoreleasePool;
+#endif
+
+// The purpose of this class us to provide a hook for platform-specific
+// operations across unit tests.  For example, on the Mac, it creates and
+// releases an outer NSAutoreleasePool for each test case.  For now, it's only
+// implemented on the Mac.  To enable this for another platform, just adjust
+// the #ifdefs and add a platform_test_<platform>.cc implementation file.
+class PlatformTest : public testing::Test {
+ public:
+  virtual ~PlatformTest();
+
+ protected:
+  PlatformTest();
+
+ private:
+  NSAutoreleasePool* pool_;
+};
+#else
+typedef testing::Test PlatformTest;
+#endif // GTEST_OS_MAC
+
+#endif // TESTING_PLATFORM_TEST_H_
diff --git a/libchrome/testrunner.cc b/libchrome/testrunner.cc
new file mode 100644
index 0000000..07117a5
--- /dev/null
+++ b/libchrome/testrunner.cc
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <gtest/gtest.h>
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit_manager;
+  base::CommandLine::Init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/libchrome/third_party/protobuf/src/google/protobuf/message_lite.h b/libchrome/third_party/protobuf/src/google/protobuf/message_lite.h
new file mode 100644
index 0000000..c472844
--- /dev/null
+++ b/libchrome/third_party/protobuf/src/google/protobuf/message_lite.h
@@ -0,0 +1 @@
+#include <google/protobuf/message_lite.h>